VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > temp > 简明python教程 >
  • 浅谈.NET中的反射

一、概述 

1、通过反射可以提供类型信息,从而使得我们开发人员在运行时能够利用这些信息构造和使用对象

2、反射机制允许程序在执行过程中动态地添加各种功能

二、运行时类型标识

1、运行时类型标志(RTTI),可以在程序执行期间判断对象类型。例如使用他能够确切的知道基类引用指向了什么类型对象。

2、运行时类型标识,能预先测试某个强制类型转换操作,能否成功,从而避免无效的强制类型转换异常。

3、在C#中有三个支持RTTI的关键字:is、as、typeof。下面一次介绍他们

is运算符:

通过is运算符,能够判断对象类型是否为特定类型,如果两种类型时相同类型,或者两者之间存在引用,装箱拆箱转换,则表明两种类型时兼容的。代码如下:

复制代码
 1         static void Main()
 2         {
 3             A a = new A();
 4             B b = new B();
 5             if (a is A)
 6             {
 7                 Console.WriteLine("a is an A");
 8             }
 9 
10             if (b is A)
11             {
12                 Console.WriteLine("b is an A because it is derived from");
13             }
14 
15             if (a is B)
16             {
17                 Console.WriteLine("This won't display,because a not derived from B");
18             }
19 
20             if (a is object)
21             {
22                 Console.WriteLine("a is an object");
23             }
24             Console.ReadKey();
25         }
复制代码

结果:

 

 as运算符:

在运行期间执行类型转换,并且能够是的类型转换失败不抛出异常,而返回一个null值,其实as也可以看作一个is运算符的简化备选方式,如下:

 

复制代码
 1         static void Main()
 2         {
 3             A a = new A();
 4             B b = new B();
 5             if (a is B)
 6             {
 7                 b = (B) a;//由于a变量不是B类型,因此这里将a变量转换为B类型时无效的
 8             }
 9             else
10             {
11                 b = null;
12             }
13 
14             if (b==null)
15             {
16                 Console.WriteLine("The cast in b=(B)a is not allowed");
17             }
18             //上面使用as运算符,能够把两部分合二为一
19             b = a as B;//as运算符先检查将之转换类型的有效性,如果有效,则执行强类型转换过程,这些都在这一句话完成
20             if (b==null)
21             {
22                 Console.WriteLine("The cast in b=(B)a is not allowed");
23             }
24             Console.ReadKey();
25         }
复制代码

结果:

 

 typeof运算符:

as、is 能够测试两种类型的兼容性,但大多数情况下,还需要获得某个类型的具体信息。这就用到了typeof,他可以返回与具体类型相关的System.Type对象,通过System.Type对象可以去定此类型的特征。一旦获得给定类型的Type对象,就可以通过使用对象定义的各自属性、字段、方法来获取类型的具体信息。Type类包含了很多成元,在接下来的反射中再详细讨论。下面简单的演示Type对象,调用它的三个属性。

 

复制代码
 1         static void Main()
 2         {
 3             Type t = typeof(StringBuilder);
 4             Console.WriteLine(t.FullName);//FullName属性返回类型的全称
 5             if (t.IsClass)
 6             {
 7                 Console.WriteLine("is a Class");
 8             }
 9 
10             if (t.IsSealed)
11             {
12                 Console.WriteLine("is Sealed");
13             }
14             Console.ReadKey();
15         }
复制代码

结果:

 

 

三、反射的核心类型:System.Type类

1、许多支持反射的类型都位于System.Reflection命名空间中,他们是.net Reflection API的一部分,所以再使用的反射的程序中一般都是要使用System.Reflection的命名空间。

2、System.Type类包装了类型,因此是整个反射子系统的核心,这个类中包含了很多属性和方法,使用这些属性和方法可以再运行时得到类型的信息。

3、Type类派生于System.Reflection.MemberInfo抽象类

MemberInfo类中的只读属性

属性

描述

Type DeclaringType

获取声明该成员的类或接口的类型

MemberTypes  MemberType

获取成员的类型,这个值用于指示该成员是字段、方法、属性、事件、或构造函数

Int MetadataToken

获取与特定元数据相关的值

Module Module

获取一个代表反射类型所在模块(可执行文件)的Module对象

String  Name

成员的名称

Type  ReflectedType

反射的对象类型

请注意:

1、MemberType属性的返回类型为MemberTypes,这是一个枚举,它定义了用于表示不同成元的信息值,这些包括:MemberTypes.Constructor、MemeberTypes.Method、MemberTypes.Event、MemberTypes.Property。因此可以通过检查MemberType属性来确定成元的类型,例如在MenberType属性的值为MemberTypes.Method时,该成员为方法

2、MemberInfo类还包含两个与特性相关的抽象方法:

(1)GetCustomAttributes():获得与主调对象相关的自定义特性列表。

(2)IsDefined():确定是否为主调对象定义了相应的特性。

(3)GetCustomeAttributesData():返回有关自定义特性的信息(特性稍后便会提到)

当然除了MemberInfo类定义的方法和属性外,Type类自己也添加了许多属性和方法:如下表(只列出一些常用的,太多二零,自己可以转定义Type类看一下)

Type类定义的方法

方法

功能

ConstructorInfo[]  GetConstructors()

获取指定类型的构造函数列表

EventInfo[]   GetEvents();

获取指定类型的时间列

FieldInfo[]   GetFields();

获取指定类型的字段列

Type[]   GetGenericArguments();

获取与已构造的泛型类型绑定的类型参数列表,如果指定类型的泛型类型定义,则获得类型形参。对于正早构造的类型,该列表就可能同时包含类型实参和类型形参

MemberInfo[]   GetMembers();

获取指定类型的成员列表

MethodInfo[]   GetMethods();

获取指定类型的方法列表

PropertyInfo[]   GetProperties();

获取指定类型的属性列表

下面列出Type类型定义的常用只读属性

Type类定义的属性

属性

功能

 Assembly   Assembly 

获取指定类型的程序集

TypeAttributes   Attributes

获取制定类型的特性

Type   BaseType

获取指定类型的直接基类型

String  FullName

获取指定类型的全名

bool   IsAbstract

如果指定类型是抽象类型,返回true

bool   IsClass

如果指定类型是类,返回true

string   Namespace

获取指定类型的命名空间

四、使用反射

上面将的这些,都是为了使用反射做铺垫的。

通过使用Type类定义的方法和属性,我们能够在运行时获得类型的各种具体信息。这是一个非常强大的功能,我们一旦得到类型信息,就可以调用其构造函数、方法、属性,可见,反射是允许使用编译时不可用的代码的。

由于Feflection API非常多,这里不可能完整的介绍他们(这里如果完整的介绍,据说要一本书,厚书)。但是Reflection API是按照一定逻辑设计的,因此,只要知道部分接口的使用方法,就可以举一反三的使用剩余的接口。

这里我列出四种关键的反射技术:

1、获取方法的信息

2、调用方法

3、构造对象

4、从程序集中加载类型

五、获取方法的相关信息

一旦有了Type对象就可以使用GetMethodInfo()方法获取此类型支持的所有方法列表。该方法返回一个MethodInfo对象数组,MethodInfo对象表述了主调类型所支持的方法,它位于System.Reflection命名空间中。MethodInfo类派生于MethodBase抽象类,而MethodBase类继承了MemberInfo类,因此,我们能够使用这三各类定义的属性和方法。例如,使用Name属性的到方法名,这里有两个重要的成员:

1、ReturnType属性:为Type类型的对象,能够提供方法的返回类型信息。

2、GetParameters()方法:返回参数列表,参数信息以数组的形式保存在PatameterInfo对象中。PatameterInfo类定义了大量表述参数信息的属性和方法,这里也累出两个常用的属性:Name(包含参数名称信息的字符串),ParameterType(参数类型的信息)。

下面代码我将使用反射获得类中的所支持的方法,还有方法的信息:

 

复制代码
 1     class Program
 2     {
 3         static void Main()
 4         {
 5             //获取描述MyClass类型的Type对象
 6             Type t = typeof(MyClass);
 7             Console.WriteLine($"Analyzing methods in {t.Name}");
 8             //MethodInfo对象在System.Reflection命名空间下
 9             MethodInfo[] mi = t.GetMethods();
10             foreach (var methodInfo in mi)
11             {
12                 //返回方法的返回类型
13                 Console.Write(methodInfo.ReturnType.Name);
14                 //返回方法的名称
15                 Console.Write($" {methodInfo.Name} (");
16                 //获取方法阐述列表并保存在ParameterInfo对象组中
17                 ParameterInfo[] pi = methodInfo.GetParameters();
18                 for (int i = 0; i < pi.Length; i++)
19                 {
20                     //方法的参数类型名称
21                     Console.Write(pi[i].ParameterType.Name);
22                     //方法的参数名
23                     Console.Write($" {pi[i].Name}");
24                     if (i+1<pi.Length)
25                     {
26                         Console.Write(", ");
27                     }
28                 }
29 
30                 Console.Write(")");
31                 Console.Write("\r\n");
32                 Console.WriteLine("--------------------------");
33             }
34             Console.ReadKey();
35         }
36     }
37 
38     class MyClass
39     {
40         private int x;
41         private int y;
42 
43         public MyClass()
44         {
45             x = 1;
46             y = 1;
47         }
48 
49         public int Sum()
50         {
51             return x + y;
52         }
53 
54         public bool IsBetween(int i)
55         {
56             if (x < i && i < y)
57             {
58                 return true;
59             }
60 
61             return false;
62         }
63 
64         public void Set(int a, int b)
65         {
66             x = a;
67             y = b;
68         }
69 
70         public void Set(double a, double b)
71         {
72             x = (int)a;
73             y = (int)b;
74         }
75 
76         public void Show()
77         {
78             System.Console.WriteLine($"x:{x},y:{y}");
79         }
80     }
复制代码

输出结果:

 

 注意:这里输出的除了MyClass类定义的所有方法外,也会显示object类定义的共有非静态方法。这是因为C#中的所有类型都继承于Object类。另外,这些信息是在程序运行时动态获得的,并不需要知道MyClass类的定义

GetMethods()方法的另一种形式

这种形式可以指定各种标记,已筛选想要获取的方法,他的通用形式为:MethodInfo[] GetMethods(BindingFlags bindingAttr)

BindingFlags是一个枚举,枚举值有(很多,这里只列出5个常用的吧)

(1)DeclareOnly:仅获取指定类定义的方法,而不获取所继承的方法

(2)Instance:获取实例方法

(3)NonPublic:获取非公有方法

(4)Public:获取共有方法

(5)Static:获取静态方法

GetMethods(BindingFlags bindingAttr)这个方法,参数可以使用 or 把两个或更多标记连接在一起,实际上至少要有Instance(或 Static)与Public(或 NonPublic)标记,否则将不会获取任何方法。下我们就写一个示例来演示一下。

复制代码
 1     class Program
 2     {
 3         static void Main()
 4         {
 5             //获取描述MyClass类型的Type对象
 6             Type t = typeof(MyClass);
 7             Console.WriteLine($"Analyzing methods in {t.Name}");
 8             //MethodInfo对象在System.Reflection命名空间下
 9             //不获取继承方法,为实例方法,·为公用的
10             MethodInfo[] mi = t.GetMethods(BindingFlags.DeclaredOnly|BindingFlags.Instance|BindingFlags.Public);
11             foreach (var methodInfo in mi)
12             {
13                 //返回方法的返回类型
14                 Console.Write(methodInfo.ReturnType.Name);
15                 //返回方法的名称
16                 Console.Write($" {methodInfo.Name} (");
17                 //获取方法阐述列表并保存在ParameterInfo对象组中
18                 ParameterInfo[] pi = methodInfo.GetParameters();
19                 for (int i = 0; i < pi.Length; i++)
20
      



  

相关教程