利用C#的反射机制动态调用DLL类库
最近由于业务要求,需要动态调用DLL类库,所以研究了一下,感觉还好也不太难,今天就把自己理解的写了一个小例子(已经通过VS2005跑通),供大家一起研究和探讨,有理解不当的地方还请高手们多多指正,谢谢啦!
好,在这之前我先把反射所需要使用的几个类给大家列一下:
1、使用Assembly类定义和加载程序集,加载在程序集清单中列出模块,以及从此程序集中查找类型并创建该类型的实例。
2、使用MethodInfo了解方法的名称、返回类型、参数、访问修饰符(如pulic 或private)和实现详细信息(如abstract或virtual)等。使用Type的GetMethods或GetMethod方法来调用特定的方法。
一、创建用于反射调用的DLL
1 using System; 2 using System.Collections.Generic; 3 using System.Text; 4 5 namespace RefDll 6 { 7 /// <summary> 8 /// 创建需要被调用的DLL类库 9 /// </summary> 10 public class RefTest 11 { 12 /// <summary> 13 /// 求和方法 14 /// </summary> 15 /// <param name="x">第一个值</param> 16 /// <param name="y">第二个值</param> 17 /// <param name="sum">结果(和)</param> 18 public void TestSum(int x,int y,out int sum) 19 { 20 sum = 0; 21 sum = x + y; 22 } 23 24 /// <summary> 25 /// 求和方法 26 /// 第二种方式 27 /// </summary> 28 /// <param name="x">第一个值</param> 29 /// <param name="y">第二个值</param> 30 /// <returns>结果(和)</returns> 31 public int TestSumTwo(int x, int y) 32 { 33 return x + y; 34 } 35 36 /// <summary> 37 /// 求和方法 38 /// 第三种方式 39 /// </summary> 40 /// <param name="x">第一个值</param> 41 /// <param name="y">第二个值</param> 42 /// <param name="sum">结果(和)</param> 43 public static void TestSumThree(int x, int y, out int sum) 44 { 45 sum = 0; 46 sum = x + y; 47 } 48 49 } 50 }
二、应用于反射的例子
注:可以创建一个控制台的工程。
1 using System; 2 using System.Collections.Generic; 3 using System.Text; 4 using System.Reflection; 5 using System.Windows.Forms; 6 using System.IO; 7 8 namespace ReflectionLesson 9 { 10 /// <summary> 11 /// 反射类 12 /// 利用反射动态调用DLL类库。 13 /// </summary> 14 public class ReflectionLesson 15 { 16 private string strDllName = ""; 17 private string strClaName = ""; 18 private string[] strMetName = null; 19 /// <summary> 20 /// 构造方法 21 /// </summary> 22 /// <param name="DllName">调用的DLL类库名</param> 23 /// <param name="ClaName">调用的类名</param> 24 /// <param name="MetName">调用的方法名(数组)</param> 25 public ReflectionLesson(string DllName, string ClaName, string[] MetName) 26 { 27 //获取调用的DLL类库 28 this.strClaName = ClaName; 29 this.strDllName = DllName; 30 this.strMetName = MetName; 31 } 32 33 /// <summary> 34 /// 利用反射动态调用DLL类库 35 /// </summary> 36 public void ReflectionTest(int x,int y) 37 { 38 Assembly ass; 39 Type type; 40 object obj; 41 if (File.Exists(Application.StartupPath + "\\" + this.strDllName + ".dll")) 42 { 43 //获取并加载DLL类库中的程序集 44 ass = Assembly.LoadFile(Application.StartupPath + "\\" + this.strDllName + ".dll"); 45 46 //获取类的类型:必须使用名称空间+类名称 47 type = ass.GetType(this.strDllName + "." + this.strClaName); 48 49 //获取类的方法:方法名称 50 MethodInfo method1 = type.GetMethod(this.strMetName[0]); 51 MethodInfo method2 = type.GetMethod(this.strMetName[1]); 52 MethodInfo method3 = type.GetMethod(this.strMetName[2]); 53 54 //对获取的类进行创建实例。//必须使用名称空间+类名称 55 obj = ass.CreateInstance(this.strDllName + "." + this.strClaName); 56 57 //开始搜索方法 58 method1 = type.GetMethod(this.strMetName[0]);//方法的名称1 59 method2 = type.GetMethod(this.strMetName[1]);//方法的名称2 60 method3 = type.GetMethod(this.strMetName[2]);//方法的名称3 61 62 object[] parts = new object[3]; 63 parts[0] = x; 64 parts[1] = y; 65 66 //方法的调用 67 //注:如果调用的DLL类库中方法是静态的,那么Invoke方法中第一个参数传值为NULL。 68 // 如果方法不是静态的,那么Invoke方法中第一个参数传值为 obj(上面那个被实例的对象) 69 method1.Invoke(obj, parts); 70 Console.WriteLine("调用的方法 " + this.strMetName[0] + ": " + x + " + " + y + " = " + parts[2]); 71 72 int sum1 = (int)method2.Invoke(obj, new object[] { x + 10, y + 10 }); 73 Console.WriteLine("调用的方法 " + this.strMetName[1] + ": " + (x + 10) + " + " + (y + 10) + " = " + sum1); 74 75 76 object[] temParts = new object[3]; 77 temParts[0] = x + 20; 78 temParts[1] = y + 20; 79 method3.Invoke(null, temParts); 80 Console.WriteLine("调用的方法 " + this.strMetName[2] + ": " + temParts[0] + " + " + temParts[1] + " = " + temParts[2]); 81 } 82 } 83 } 84 }
在Main 函数中可以输入以下代码:
1 using System; 2 using System.Collections.Generic; 3 using System.Text; 4 using System.Windows.Forms; 5 namespace ReflectionLesson 6 { 7 class Program 8 { 9 static void Main(string[] args) 10 { 11 string dllname = "RefDll"; 12 string claname ="RefTest"; 13 string[] metname = new string[]{"TestSum","TestSumTwo","TestSumThree"}; 14 ReflectionLesson refl = new ReflectionLesson(dllname, claname, metname); 15 refl.ReflectionTest(100,200); 16 } 17 } 18 }
好了。现在可以跑一下如何调用的了,大家可以设置在调试模式下进行阅读代码。
=========================================================================
反射的作用: 1. 可以使用反射动态地创建类型的实例,将类型绑定到现有对象,或从现有对象中获取类型 2. 应用程序需要在运行时从某个特定的程序集中载入一个特定的类型,以便实现某个任务时可以用到反射。 3. 反射主要应用与类库,这些类库需要知道一个类型的定义,以便提供更多的功能。
1 需要反射的DLL
1 using System; 2 namespace Webtest 3 { 4 public class ReflectTest 5 { 6 public ReflectTest(){} 7 public string WriteString(string s) 8 { 9 return "欢迎您," + s; 10 } 11 //静态函数 12 public static string WriteName(string s) 13 { 14 return "欢迎您光临," + s; 15 } 16 //不带参数的函数 17 public string WriteNoPara() 18 { 19 return "您使用的是无参数方法"; 20 } 21 } 22 }
应用于反射的例子-在ASPNET页面中加入以下函数:
1 public void test1() 2 { 3 System.Reflection.Assembly ass; 4 Type type ; 5 object obj; 6 try 7 { 8 ass = System.Reflection.Assembly.LoadFile(@"d:\TestReflect.dll");//要绝对路径 9 type = ass.GetType("Webtest.ReflectTest");//必须使用 名称空间+类名称 10 System.Reflection.MethodInfo method = type.GetMethod("WriteString");//方法的名称 11 obj = ass.CreateInstance("Webtest.ReflectTest");//必须使用名称空间+类名称 12 string s = (string)method.Invoke(obj,new string[]{"jianglijun"}); // 实例方法的调用 13 或:string s = (string)method.Invoke(obj,Object[] parametors = new Object[]{"param"}); 14 Response.Write(s+"<br>"); 15 method = type.GetMethod("WriteName");//方法的名称 16 s = (string)method.Invoke(null,new string[]{"jianglijun"}); // 静态方法的调用 17 Response.Write(s+"<br>"); 18 19 method = type.GetMethod("WriteNoPara");//无参数的实例方法 20 s = (string)method.Invoke(obj,null); 21 Response.Write(s+"<br>"); 22 method = null; 23 } 24 catch(Exception ex) 25 { 26 Response.Write(ex+"<br>"); 27 } 28 finally 29 { 30 ass = null; 31 type = null; 32 obj = null; 33 } 34 }