最近一直都在看关于程序集加载和反射方面的资料, 所以在这里把我所学习到的东西记录下来,方便自己以后复习,也给园子里面不懂的朋友参考。
一、程序集的加载
JIT编译器器将IL代码编译成本地代码时, 会查看IL代码中引用了哪些类型。在运行过程中,JIT编译器利用程序集的TypeRef和AssemblyRef元数据表来确定哪一个程序集定义了所引用的类型,然后JIT编译器将对应程序集加载到AppDomain中,在内部,CLR使用System.Reflection.Assembly类的静态方法Load来尝试加载一个程序集。然而如果我们想动态加载一个程序集时,可以使用Assembly的Load方法来动态加载程序集,其中Assembly类中还提供了其他的加载程序集方法,有LoadFrom(string path), LoadFile(stringassemblyFile)等,具体方法的使用和解释可以参照MSDN中的介绍:
二、反射机制
.net中反射在运行中过程中解析程序集中的元数据,获得类型中的成员(包括字段、构造器、方法、属性、事件等)信息。
动态加载一个程序集并获得类型中的成员
把下面的类放在一个类库工程中,并编译生成程序集(例如为ClassLibrary1.dll,假设把dll放在D盘根目录下面)
1 public class ReflectTestClass 2 { 3 public string name; 4 public int age; 5 public string Name 6 { 7 get { return name; } 8 set { name = value; } 9 }10 11 public int Age12 {13 get { return age; }14 set { age = value; }15 }16 17 ///18 /// No Paramter Constructor19 /// 20 public ReflectTestClass()21 { 22 }23 24 ///25 /// Constructor with Parameter26 /// 27 /// 28 /// 29 public ReflectTestClass(string names,int ages)30 {31 this.name = names;32 this.age = ages;33 }34 35 public string writeString(string name)36 {37 return "Welcome " + name;38 }39 40 public static string WriteName(string name)41 {42 return "Welcome "+name +" Come here";43 }44 45 public string WirteNopara()46 {47 return "The method is no parameter ";48 }49 }
然后建立一个控制台程序用来动态加载上面生成的程序集和输出类型中的成员,代码中有详细的介绍。
class Program { static void Main(string[] args) { Assembly ass; Type[] types; Type typeA; object obj; try { // 从本地中 加载程序集 然后从程序集中通过反射获得类型的信息的,并且调用方法 ass = Assembly.LoadFrom(@"D:\ClassLibrary1.dll"); types = ass.GetTypes(); foreach (Type type in types) { Console.WriteLine("Class Name is " + type.FullName); Console.WriteLine("Constructor Information"); Console.WriteLine("-----------------------"); // 获取类型的结构信息 ConstructorInfo[] myconstructors = type.GetConstructors(); ShowMessage(myconstructors); Console.WriteLine("Fields Information"); Console.WriteLine("-----------------------"); // 获取类型的字段信息 FieldInfo[] myfields = type.GetFields(); ShowMessage (myfields); Console.WriteLine("All Methods Information"); Console.WriteLine("-----------------------"); // 获取方法信息 MethodInfo[] myMethodInfo = type.GetMethods(); ShowMessage (myMethodInfo); Console.WriteLine("All Properties Information"); Console.WriteLine("-----------------------"); // 获取属性信息 PropertyInfo[] myproperties = type.GetProperties(); ShowMessage (myproperties); } // 用命名空间+类名获取类型 typeA = ass.GetType("ClassLibrary1.ReflectTestClass"); // 获得方法名称 MethodInfo method = typeA.GetMethod("writeString"); // 创建实例 obj = ass.CreateInstance("ClassLibrary1.ReflectTestClass"); string result = (String)method.Invoke(obj,new string[] { "Tom"}); Console.WriteLine("Invoke Method With Parameter"); Console.WriteLine("-----------------------"); Console.WriteLine(result); Console.WriteLine("-----------------------"); Console.WriteLine(); method = typeA.GetMethod("WriteName"); result = (string)method.Invoke(null,new string[] { "Tom"}); Console.WriteLine("Invoke Static Method with Parameter"); Console.WriteLine("-----------------------"); Console.WriteLine(result); Console.WriteLine("-----------------------"); Console.WriteLine(); method = typeA.GetMethod("WirteNopara"); Console.WriteLine("Invoke Method with NOParameter"); result = (string)method.Invoke(obj, null); Console.WriteLine("-----------------------"); Console.WriteLine(result); Console.WriteLine("-----------------------"); } catch(FileNotFoundException ex) { Console.WriteLine(ex.Message); } Console.ReadLine(); } /// /// 显示数组信息 /// ////// public static void ShowMessage (T[] array) { foreach(T member in array) { Console.WriteLine(member.ToString()); } Console.WriteLine("-----------------------"); Console.WriteLine(); } }
可以调用Type的GetMembers,GetFields,GetMethods,GetProperties或者GetEvenents方法来查询一个类型的成员。在调用上面的任何一个方法时,都可以传递System.Reflection.BindingFlags枚举类型的一个实例,使用这个枚举类型目的是对这些方法返回的成员进行筛选。对于这个枚举类型中成员的信息可以参考MSDN:
注意:在返回一个成员集合的所有方法中, 都有一个不获取任何实参的重载版本。如果不传递BindingFlags实参,所有这些方法都返回公共成员,默认设置为BindingFlags.Public|BindingFlags.Instance|BindingFlags.Static. (如果指定Public或NonPublic,那么必须同时指定Instance,否则不返回成员)。