反射
使用反射,可以在程序运行时创建、调用和访问类型实例。
可以使用反射动态地创建类型的实例,将类型绑定到现有对象,或从现有对象中获取类型。
简单的来说,就是平常我们创建类实例,访问类成员函数、变量等,都是在开发环境中写好代码再去执行。使用反射后,可以在程序运行时,执行上述操作。
反射有时候也会用,这算是一个比较系统的总结了吧。
反射的典型用法
-
Assembly 来定义和加载程序集,加载程序集清单中列出的模块,以及在此程序集中定位一个类型并创建一个它的实例。
-
还可以获取所有全局方法或模块上定义的其它特定的非全局方法。
-
GetConstructor 方法来调用特定构造函数。
-
GetMethod 方法来调用特定方法。
-
FieldInfo 发现信息,如名称、访问修饰符(如
public或private)和一个字段的实现详细信息 (如static);并获取或设置字段值。 -
EventInfo 发现信息(如名称、事件处理程序的数据类型、自定义特性、声明类型以及事件的反射的类型),并添加或删除事件处理程序。
-
PropertyInfo 发现信息(如名称、数据类型、声明类型,反射的类型和属性的只读或可写状态),并获取或设置属性值。
-
ParameterInfo 发现信息,如参数的名称、数据类型、参数是输入参数还是输出参数以及参数在方法签名中的位置。
-
CustomAttributeData 使你能够检查特性,而无需创建它们的实例。
System.Type
表示类型声明:类类型、接口类型、数组类型、值类型、枚举类型、类型参数、泛型类型定义,以及开放或封闭构造的泛型类型
Type是一个抽象的基类,实例化了一个Type对象,实际上就实例化了Type的一个派生类。
获取给定类型的Type引用有3种常用方式:
1、使用typeof运算符
1 var strType = typeof(string);
2、使用GetType()方法,所有的类都会从System.Object继承这个方法
1 string str = "HelloWorld"; 2 var strType2 = str.GetType();
3、使用Type类的静态方法GetType
1 var t = Type.GetType("System.String");
System.Type常用属性
| 属性 | 返回值 |
| Name | 数据类型名 |
| FullName | 数据类型的完全限定名(包括命名空间) |
| Namespace | 数据类型的命名空间 |
| BaseType |
该Type的直接基本类型 |
| Module | 该类型的模块 (DLL) |
| Assembly | 该类型的 Assembly |
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 var t = Type.GetType("System.String"); 6 Console.WriteLine(t); 7 8 9 Console.WriteLine("Name:" + t.Name); 10 Console.WriteLine("FullName:" + t.FullName); 11 Console.WriteLine("Namespce:" + t.Namespace); 12 Console.WriteLine("BaseType:" + t.BaseType); 13 Console.WriteLine("Assembly:" + t.Assembly.FullName); 14 Console.WriteLine("Module:" + t.Module.Name); 15 } 16 }
Type类包含许多Is开头的属性,这些属性用于判断该Type是否属于该类型。常用的如下:
| 属性 | 说明 |
| IsAbstract |
是否是抽象类型 |
| IsArray |
是否为数组 |
| IsByRef |
是否是引用传递 |
| IsClass |
是否是一个类或委托 |
| IsCOMObject |
是否为 COM 对象 |
| IsConstructedGenericType |
|
| IsContextful |
指示 Type 在上下文中是否可以被承载 |
| IsEnum |
是否是枚举 |
| IsExplicitLayout |
是否放置在显式指定的偏移量处的值 |
| IsGenericMethodParameter |
是否表示泛型方法定义中的类型参数 |
| IsGenericParameter |
是否表示泛型类型或方法的定义中的类型参数 |
| IsGenericType |
是否是泛型类型 |
| IsGenericTypeDefinition |
是否表示可以用来构造其他泛型类型的泛型类型定义 |
| IsGenericTypeParameter |
是否表示泛型类型定义中的类型参数 |
| IsImport |
是否应用了 ComImportAttribute 属性 |
| IsInterface |
是否是接口 |
| IsLayoutSequential |
是否按顺序(定义顺序或发送到元数据的顺序)放置的值 |
| IsMarshalByRef |
是否按引用进行封送 |
| IsNested |
是否表示其定义嵌套在另一个类型的定义之内的类型的值 |
| IsNestedAssembly |
是否是嵌套的并且只能在它自己的程序集内可见 |
| IsPointer |
是否是指针 |
| IsPrimitive |
是否为基元类型之一 |
| IsPublic |
是否声明为公共类型 |
| IsSealed |
是否声明为密封的 |
| IsSerializable |
是否为可序列化的 |
| IsValueType |
是否为值类型 |
| IsVisible |
是否可由程序集之外的代码访问的值 |
System.Type常用方法
System.Type的大多数方法都用于获取对应数据类型的成员信息:构造函数、属性、方法和事件等。
| 方法 | 说明 |
| GetConstructors | 获取所有公共构造函数 |
| GetEvents | 获取所有公共事件所有公共事件 |
| GetFields | 获取所有公共字段 |
| GetMembers | 获取所有公共成员 |
| GetMethods | 获取所有公共方法 |
| GetProperties | 获取所有公共属性 |
这里我们用WPF的Button类来进行演示:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 namespace ReflectionDemo 8 { 9 class Program 10 { 11 static void Main(string[] args) 12 { 13 var buttonType = typeof(System.Windows.Controls.Button); 14 15 var ctors = buttonType.GetConstructors(); 16 var events = buttonType.GetEvents(); 17 var fields = buttonType.GetFields(); 18 var members = buttonType.GetMembers(); 19 var methods = buttonType.GetMethods(); 20 var properties = buttonType.GetProperties(); 21 22 Console.WriteLine(buttonType.Assembly.FullName); 23 PrintResult(ctors, "Constructors"); 24 PrintResult(events, "Events"); 25 PrintResult(fields, "Fields"); 26 PrintResult(members, "Members"); 27 PrintResult(methods, "Methods"); 28 PrintResult(properties, "Properties"); 29 } 30 31 static void PrintResult(object[] array, string title = "") 32 { 33 Console.WriteLine(title); 34 foreach (var item in array) 35 { 36 Console.WriteLine(item); 37 } 38 Console.WriteLine(); 39 Console.WriteLine(); 40 } 41 } 42 }
此外,System.Type还提供了单数形式的方法,如t.GetMethod()、t.GetEvent()。单数形式的方式用于返回指定名称的值。
如:
1 var buttonType = typeof(System.Windows.Controls.Button); 2 var clickEvent = buttonType.GetEvent("Click");
在前面的示例代码中,我们输出 了string类型的Assembly,如下:
1 Assembly:mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
mscorlib.dll是我们引用的程序集,如果需要加载外部 程序集并获取类型信息,就需要使用Assembly类
System.Reflection.Assembly
Assembly类允许访问给定程序集的元数据,同时它也包含可以加载程序集的方法。
要将程序集加载到正在运行的程序中,可以通过两个方法:Assembly.Load()和Assembly.LoadFrom()。
这两个方法的区别是:
Assembly.Load()的参数是指定程序集名称,运行库会在各个位置(运行目录和GAC)搜索该程序集,试图找到该程序集。
Assembly.LoadFrom()的参数是指定程序集的完整路径,它不会在其它位置搜索该程序集
推荐阅读:
反射
https://docs.microsoft.com/zh-cn/dotnet/framework/reflection-and-codedom/reflection