.Net中的反射

反射

使用反射,可以在程序运行时创建、调用和访问类型实例。 

程序集(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()的参数是指定程序集的完整路径,它不会在其它位置搜索该程序集

 

 

如何判断类型是否实现了某个接口

1 typeof(XXInterface).IsAssignableFrom(XXType)

 

如何调用带有out参数的方法

这里以数值类型的TryParse函数为例

parameters[1]就是out返回的参数

 1 var tryParseFunc = xxxx;
 2 
 3             if(tryParseFunc != null)
 4             {
 5                 object[] parameters = new object[] { getValue.ToString(), null };
 6                 object result = tryParseFunc.Invoke(null, parameters);
 7                 bool blResult = (bool)result;
 8                 if (blResult)
 9                 {
10                     //parameters[1];
11                 }
12             }

 

如何获取可空类型的实际声明类型

Nullable<int>/int?在获取type时,会返回Nullable,而不是int。可以用下面的方法获取int类型

1      public static Type GetNullableDeclaringType(Type type)
2         {
3             if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
4             {
5                 return Nullable.GetUnderlyingType(type);
6             }
7 
8             return type;
9         }

 

推荐阅读:

反射

https://docs.microsoft.com/zh-cn/dotnet/framework/reflection-and-codedom/reflection

posted @ 2020-12-11 18:29  zhaotianff  阅读(344)  评论(0编辑  收藏  举报