上篇文章主要介绍了程序集的内容:程序集和反射(一),时隔这么久,今天终于腾出点时间,把反射部分的知识点给整理一下,不把这个写完,心里总觉得有点堵。对于反射,我相信很多人跟LZ一个德行,不会,所以不用,不用,所以永远不会。
通过System.Reflection命名空间中的类已经System.Type,您可以获取有关已加载的程序集和在其中定义的类型(如类、接口、值类型)的信息。您也可以使用反射在运行时创建类型实例,以及调用和访问这些实例。
程序集包含模块,而模块包含类型,类型又包含成员。 反射则提供了封装程序集、模块和类型的对象。 您可以使用反射动态地创建类型的实例,将类型绑定到现有对象,或从现有对象中获取类型。 然后,可以调用类型的方法或访问其字段和属性。
反射通常具有以下用途:
-
类型 作用 Assembly 定义和加载程序集,加载在程序集清单中列出的模块,以及从此程序集中查找类型并创建该类型的实例。用来获取程序集内部信息 EventInfo 发现以下信息:事件的名称、事件处理程序数据类型、自定义特性、声明类型和反射类型等;并添加或移除事件处理程序。 FieldInfo 发现以下信息:字段的名称、访问修饰符(如 public 或 private)和实现详细信息(如 static)等;并获取或设置字段值 。该类保存给定的字段信息 MethodInfo 发现以下信息:方法的名称、返回类型、参数、访问修饰符(如 public 或 private)和实现详细信息(如 abstract 或 virtual)等。 使用 Type 的 GetMethods 或 GetMethod 方法来调用特定的方法。该类保存给定的方法信息 MemberInfo 该类是一个基类,它定义了EventInfo、FieldInfo、MethodInfo、PropertyInfo的多个公用行为 Module 发现以下信息:包含模块的程序集以及模块中的类等。 您还可以获取在模块上定义的所有全局方法或其他特定的非全局方法。该类可以使你能访问多个程序集中的给定模块 ParameterInfo 发现以下信息:参数的名称、数据类型、参数是输入参数还是输出参数,以及参数在方法签名中的位置等。该类保存给定的参数信息 PropertyInfo 发现以下信息:属性的名称、数据类型、声明类型、反射类型和只读或可写状态等;并获取或设置属性值。该类保存给定的属性信息 - 使用 ConstructorInfo 发现以下信息:构造函数的名称、参数、访问修饰符(如 public 或 private)和实现详细信息(如 abstract 或 virtual)等。 使用 Type 的 GetConstructors 或 GetConstructor 方法来调用特定的构造函数。(以上内容参考MSDN)
Type类
表示类型声明:类类型、接口类型、数组类型、值类型、枚举类型、类型参数、泛型类型定义,以及开放或封闭构造的泛型类型。
可以通过以下两种方式获得Type:
1.通过类获得Type: Type t=typeof(Person);
2.通过对象获得Type:Person p=new Person(); Type t=p.GetType();
这里仍然采用上篇文章中的示例:
1 static void Main(string[] args) 2 { 3 //通过反射动态调用另一个程序集中的方法 4 //1加载程序集 5 string path = AppDomain.CurrentDomain.BaseDirectory;//获取当前.exe执行文件的路径 6 path = Path.Combine(path, "MyAssembly.dll");//拼接程序集的路径 7 Assembly assembly = Assembly.LoadFile(path); 8 //2创建Person类的对象 9 Type type = assembly.GetType("MyAssembly.Person"); 10 object o = Activator.CreateInstance(type,"wolf",22,"未知");//实例化 11 //3获取方法的类型 12 MethodInfo methodInfo = type.GetMethod("SayHi"); 13 //4反射调用方法 14 methodInfo.Invoke(o, null); 15 Console.Read(); 16 }
调用Assembly的GetExportedTypes方法可以得到Assembly中定义的所有的public类型。
调用Assembly的GetTypes()方法可以得到Assembly中定义的所有的类型。
调用Assembly的GetType(name)方法可以得到Assembly中定义的全名为name的类型信息。如: Type type = assembly.GetType("MyAssembly.Person");
动态创建对像
Activator.CreateInstance(Type t)会动态调用类的无参构造函数创建一个对象,返回值就是创建的对象,如果类没有无参构造函数就会报错。
GetConstructor(参数列表);//这个是找到带参数的构造函数。例如:object o = Activator.CreateInstance(type,"wolf",22,"未知");//实例化
Type类的方法
bool IsAssignableFrom(Type c):判断当前的类型的变量是不是可以接受c类型变量的赋值。
1 Type type = assembly.GetType("MyAssembly.Person"); 2 Type studentType = assembly.GetType("MyAssembly.Student"); 3 Console.WriteLine(type.IsAssignableFrom(studentType));
Result:True 因为Person p=new Student();
typeof(IPlugin).IsAssignableFrom(t)
bool IsInstanceOfType(object o):判断对象o是否是当前类的实例(当前类可以是o的类、父类、接口)
Person p = new Student(); //判断p是否是一个Student类的实例 bool r = typeof(Student).IsInstanceOfType(p);//True
bool IsSubclassOf(Type c):判断当前类是否是类c的子类。实用于类,不适用于接口
//判断Student是否是Person的子类 bool r = typeof(Student).IsSubclassOf(typeof(Person));//Tru
IsAbstract,判断是否为抽象的,含接口
//判断Person是否是抽象类或接口 bool r = typeof(Person).IsAbstract;//False
动态调用成员
MemberInfo类 抽象类,有很多子类,下面讲的类都继承自它,获取程序集成员的相关信息(类型、方法、事件、字段和属性)
PropertyInfo 获取属性
主要成员:CanRead、CanWrite、PropertyType属性类型;SetValue、GetValue:读取值,设置值,第一个参数是实例对象,因为set、get要针对具体实例,最后一个参数null。pInfo.SetValue(p1, 30, null)
MethodInfo 获取方法
MethodInfo 都是和具体对象不相关的,所以需要第一个参数指定要执行的对象。
//3获取方法的类型 MethodInfo methodInfo = type.GetMethod("SayHi");
FieldInfo 获取字段
EventInfo 获取事件
案例:
<?xml version="1.0" encoding="utf-8" ?> <Persons> <person> <Name>wolfy1</Name> <Age>22</Age> <Gender>男</Gender> </person> <person> <Name>wolfy2</Name> <Age>23</Age> <Gender>女</Gender> </person> <person> <Name>wolfy3</Name> <Age>24</Age> <Gender>未知</Gender> </person> </Persons>
控制台程序测试程序:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.IO; 6 using System.Reflection; 7 using System.Xml; 8 using System.Xml.Linq; 9 namespace AssemblyDemo 10 { 11 class Program 12 { 13 14 static void Main(string[] args) 15 { 16 //通过反射动态调用另一个程序集中的方法 17 //1加载程序集 18 string path = AppDomain.CurrentDomain.BaseDirectory;//获取当前.exe执行文件的路径 19 string xmlPath = Path.Combine(path, "Person.xml"); 20 path = Path.Combine(path, "MyAssembly.dll");//拼接程序集的路径 21 XElement xml; 22 Assembly assembly = Assembly.LoadFile(path); 23 xml = XElement.Load(xmlPath); 24 //2创建Person类的对象 25 Type type = assembly.GetType("MyAssembly.Person"); 26 foreach (var item in xml.Elements("person")) 27 { 28 PropertyInfo[] properties = type.GetProperties(); 29 foreach (PropertyInfo p in properties) 30 { 31 Console.Write(item.Element(p.Name).Value+" "); 32 } 33 Console.WriteLine(); 34 } 35 Console.Read(); 36 } 37 } 38 }
结果:
结语:
关于程序集和反射的基础,就介绍到这里,怎么样去掌握,还得勤思考,多用才行。