.net反射总结

 

1.什么是反射(Reflection) 

反射和c++的CRunTime有点类似实现了动态识别和生成对象(http://www.yesky.com/79/27579.shtml这个作者有点不厚道,这篇文章和《深入浅出MFC》有出入),CRuntime的实现方法是将自己插入每一个类中,将所有的类连成一个链表,当输入类型名称的时候(下面的实例中,这个类型名称是从xml中读取的),遍历整个链表,如果找到相应的类型,则创建相应的实例。我想.net可以在运行时获得.NET中每一个类型(包括类、结构、委托、接口和枚举等)的成员,包括方法、属性、事件,以及构造函数等,并且可以获得每个成员的名称、限定符和参数等,应该也类似的实现吧!毕竟c#是c++的孩子吧!(我也就做了几个月的c#开发,有出入请各位一定要帮助纠正,这也是我写博文的初衷!本人表达能力较差,也希望各位纠正!) 

  .NET应用程序结构分为应用程序域/程序集模块/类型/成员几个层次,公共语言运行库加载器管理应用程序域,这种管理包括将每个程序集加载到相应的应用程序域以及控制每个程序集中类型层次结构的内存布局。而反射机制则提供一种编程方式,让我们可以在运行期获得各个组成部分的相关信息。.net提供了获得相应这些相关信息的类,如下:  

(1)使用Assembly定义和加载程序集,加载在程序集清单中列出模块,以及从此程序集中查找类型并创建该类型的实例。
(2)使用Module了解包含模块的程序集以及模块中的类等,还可以获取在模块上定义的所有全局方法或其他特定的非全局方法。
(3)使用ConstructorInfo了解构造函数的名称、参数、访问修饰符(如pulic 或private)和实现详细信息(如abstract或virtual)等。使用 Type的GetConstructors或GetConstructor方法来调用特定的构造函数。
(4)使用MethodInfo了解方法的名称、返回类型、参数、访问修饰符(如pulic 或private)和实现详细信息(如abstract或virtual)等。使用Type的GetMethods或GetMethod方法来调用特定的方法。
(5)使用FiedInfo了解字段的名称、访问修饰符(如public或private)和实现详细信息(如static)等,并获取或设置字段值。
(6)使用EventInfo了解事件的名称、事件处理程序数据类型、自定义属性、声明类型和反射类型等,添加或移除事件处理程序。
(7)使用PropertyInfo了解属性的名称、数据类型、声明类型、反射类型和只读或可写状态等,获取或设置属性值。
(8)使用ParameterInfo了解参数的名称、数据类型、是输入参数还是输出参数,以及参数在方法签名中的位置等。  

 上面的简单介绍清楚描述了各个类的功能用途。

 下面是简单的应用(转):

 1.如何使用反射获取类型
首先我们来看如何获得类型信息。获得类型信息有两种方法。

 一种是得到实例对象,这个时侯我仅仅是得到这个实例对象,得到的方式也许是一个object的引用,也许是一个接口的引用,但是我并不知道它的确切类型,我需要了解,那么就可 以通过调用System.Object上声明的方法GetType来获取实例对象的类型对象,比如在某个方法内,我需要判断传递进来的参数是否实现了某个接口,如果实现了,则调用该接口的一个方法:

 
public void Process( object processObj )
{
Type t = processsObj.GetType();
if( t.GetInterface(“ITest”) !=null )

}
 
另外一种获取类型的方法是通过Type.GetType以及Assembly.GetType方法,如:
 

Type t = Type.GetType(“System.String”);
需要注意的是,前面我们讲到了命名空间和装配件的关系,要查找一个类,必须指定它所在的装配件,或者在已经获得的Assembly实例上面调用GetType。
本装配件中类型可以只写类型名称,另一个例外是mscorlib.dll,这个装配件中声明的类型也可以省略装配件名称(.Net装配件编译的时候,默认都引用了mscorlib.dll,除非在编译的时候明确指定不引用它),比如:
System.String是在mscorlib.dll中声明的,上面的
 

Type t = Type.GetType(“System.String”) 

是正确的 

System.Data.DataTable是在System.Data.dll中声明的,那么:
Type.GetType(“System.Data.DataTable”)
 

就只能得到空引用。必须: 

Type t = Type.GetType("System.Data.DataTable,System.Data,Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"); 

这样才可以。 

2.如何根据类型来动态创建对象
System.Activator提供了方法来根据类型动态创建对象,比如创建一个DataTable:
 

Type t = Type.GetType("System.Data.DataTable,System.Data,Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
DataTable table = (DataTable)Activator.CreateInstance(t);
 

例二:根据有参数的构造器创建对象 

namespace TestSpace
{
public class TestClass
{
private string _value;
public TestClass(string value)
{
_value=value;
}
}
}

Type t = Type.GetType(“TestSpace.TestClass”);
Object[] constructParms = new object[] {“hello”}; //构造器参数
TestClass obj = (TestClass)Activator.CreateInstance(t,constructParms);

把参数按照顺序放入一个Object数组中即可

3.
如何获取方法以及动态调用方法
 

namespace TestSpace
{
public class TestClass {
private string _value;
public TestClass() {
}
public TestClass(string value) {
_value = value;
}
public string GetValue( string prefix ) {
if( _value==null )
return "NULL";
else
return prefix+" : "+_value;
}
public string Value {
set {
_value=value;
}
get {
if( _value==null )
return "NULL";
else
return _value;
}
}
}
}
 

上面是一个简单的类,包含一个有参数的构造器,一个GetValue的方法,一个Value属性,我们可以通过方法的名称来得到方法并且调用之,如: 

//获取类型信息
Type t = Type.GetType("TestSpace.TestClass");
//构造器的参数
object[] constuctParms = new object[]{"timmy"};
//根据类型创建对象
object dObj = Activator.CreateInstance(t,constuctParms);
//获取方法的信息
MethodInfo method = t.GetMethod("GetValue");
//调用方法的一些标志位,这里的含义是Public并且是实例方法,这也是默认的值
BindingFlags flag = BindingFlags.Public | BindingFlags.Instance;
//GetValue方法的参数
object[] parameters = new object[]{"Hello"};
//调用方法,用一个object接收返回值
object returnValue = method.Invoke(dObj,flag,Type.DefaultBinder,parameters,null);
 

属性与方法的调用大同小异,大家也可以参考MSDN 

4.动态创建委托
委托是C#中实现事件的基础,有时候不可避免的要动态的创建委托,实际上委托也是一种类型:System.Delegate,所有的委托都是从这个类派生的System.Delegate提供了一些静态方法来动态创建一个委托,比如一个委托:

namespace TestSpace {
delegate string TestDelegate(string value);
public class TestClass {
public TestClass() {
}
public void GetValue(string value) {
return value;
}
}
}
 

使用示例: 

TestClass obj = new TestClass();
//获取类型,实际上这里也可以直接用typeof来获取类型
Type t = Type.GetType(“TestSpace.TestClass”);
//创建代理,传入类型、创建代理的对象以及方法名称
TestDelegate method = (TestDelegate)Delegate.CreateDelegate(t,obj,”GetValue”);
String returnValue = method(“hello”);
 

2.为什么使用反射 

  从上面的例子或多或少都了解了一些反射的巧妙,为什么要使反射呢?使用反射可以使得我们很容易地使用自己或第三方开发的类型来增强应用程序的功能,从而设计出可动态扩展的应用程序。 

3.使用反射注意要点 

注意1:这里可反射的成员可包括私有成员,可以利用将枚举类型BindingFlags作为参数传给重载的GetMembers方法。但是这种权利不应当被滥用,.NET Reflection采用了CAS机制(代码访问安全机制)保证了这点。(枚举类型BindingFlags的说明详见 MSDN) 

注意2:使用反射来调用方法或者访问字段和属性等会造成性能的下降,原因有四: 

1)在查找成员时,绑定操作会导致频繁的字符串比较; 

2)在传递参数时,需要先构造一个数组并初始化其中的元素。然后在内部方法调用时,反射机制又要从数组中提取参数,并将它们放到堆栈上; 

3)CLR检查传入方法的参数个数与类型带来的性能开销; 

4)CLR确保调用者有适当的安全许可来访问成员带来的性能开销。

 

 

 

posted @ 2012-02-23 23:02  OctoberS  阅读(212)  评论(0)    收藏  举报