反射
使用反射,可以在程序运行时创建、调用和访问类型实例。
程序集(Assembly)包含模块(Module)、模块包含类型(Type),而类型包含成员(Member)。 可以使用反射动态地创建类型的实例,将类型绑定到现有对象,或从现有对象中获取类型。
简单的来说,就是平常我们创建类实例,访问类成员函数、变量等,都是在开发环境中写好代码再去执行。使用反射后,可以在程序运行时,执行上述操作。
反射有时候也会用,这算是一个比较系统的总结了吧。
反射的典型用法
-
使用 Assembly 来定义和加载程序集,加载程序集清单中列出的模块,以及在此程序集中定位一个类型并创建一个它的实例。
-
使用 Module 发现信息,如包含模块的程序集和模块中的类。 还可以获取所有全局方法或模块上定义的其它特定的非全局方法。
-
使用 ConstructorInfo 发现信息,如名称、参数、访问修饰符(如
public
或private
)和构造函数的实现详细信息(如abstract
或virtual
)。 使用 Type 的 GetConstructors 或 GetConstructor 方法来调用特定构造函数。 -
使用 MethodInfo 发现信息,如名称、返回类型、参数、访问修饰符(如
public
或private
)和方法的实现详细信息(如abstract
或virtual
)。 使用 Type 的 GetMethods 或 GetMethod 方法来调用特定方法。 -
使用 FieldInfo 发现信息,如名称、访问修饰符(如
public
或private
)和一个字段的实现详细信息 (如static
);并获取或设置字段值。 -
使用 EventInfo 发现信息(如名称、事件处理程序的数据类型、自定义特性、声明类型以及事件的反射的类型),并添加或删除事件处理程序。
-
使用 PropertyInfo 发现信息(如名称、数据类型、声明类型,反射的类型和属性的只读或可写状态),并获取或设置属性值。
-
使用 ParameterInfo 发现信息,如参数的名称、数据类型、参数是输入参数还是输出参数以及参数在方法签名中的位置。
-
使用 CustomAttributeData 在于应用程序域的仅反射上下文中工作时发现有关自定义特性的信息。 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