反射可以动态的创建类型的实例,将类型绑定现有对象,或是从现有对象中取得类型。利用反射主要可以取得MemberInfo,EventInfo,FieldInfo,MethodBase,MethodInfo,ConstructorInfo,PropertyInfo等等。应用程序从某个程序集中载入相应的类型对象,实现对反射的应用,反射主要应用于类库,当类库知道类型定义的时候,可以提供更多的功能。反射主要是通过程序集取得模块,然后由模块取得相应的类型,通过类型获取该类库中的Event,Member,function,property等等一些我们要使用的东西,这就是反射的层次模型。如下图所示:
Type |
Assembly |
Module |
Event |
Field |
Feature |
Function |
使用反射有一定利弊,现实应用程序中很少有应用程序需要使用反射类型使用反射动态绑定,但是需要牺牲性能有些元数据信息是不能通过反射获取的某些反射类型是专门为那些clr 开发编译器的开发使用的,所以反射不是任何时候都能够使用的,必须根据自己的需求来使用反射。
下面介绍一下具体的反射实例:
(1) 反射AppDomain的程序集
foreach (Assembly assem in Appdomain.currentDomain.GetAssemblies()
{
reflector.ReflectOnAssembly(assem)
}
(2) 反射单个程序集
主要有三种方法:
1) Load 方法:Load 方法带有一个程序集标志并载入它,Load 将引起CLR把策略应用到程序集上,先后在全局程序集缓冲区,应用程序集目录和私有路径下面查找该程序集,如果找不到该程序集系统抛出异常
2) LoadFrom 方法:传递一个程序集文件的路径名(包括扩展名),CLR会载入您指定的这个程序集,传递的这个参数不能包含任何关于版本号的信息,区域性,和公钥信息,如果在指定路径找不到程序集抛出异常。
3) LoadWithPartialName:永远不要使用这个方法,因为应用程序不能确定再在载入的程序集的版本。该方法的唯一用途是帮助那些在.Net框架的测试环节使用.net 框架提供的某种行为的客户,这个方法将最终被抛弃不用。
注意:system.AppDomain 也提供了一种Load 方法,他和Assembly的静态Load 方法不一样,AppDomain的load 方法是一种实例方法,返回的是一个对程序集的引用,Assembly的静态Load 方发将程序集按值封装发回给发出调用的AppDomain.尽量避免使用AppDomain的load 方法。
(3) 使用反射获取类型信息
static void Main(string[]args)
{
TestReflect reflect=new TestReflect();
Assembly assembly =assembly.loadfrom(“testreflect.exe”)
reflect.getreflectioninfo(assembly);
}
void getreflectioninfo(Assembly assembly)
{
Type[] types=assemby.Gettypes();
foreach (Type type in types)
{
Constructorinfo[] constructors=type.GetConstructors;
Fieldinfo[] fields=type.GetFiedls()
MethodInfo [] methodInfo=type.GetMethods();
propertyInfo[] properties=type.GetProperties();
EventInfo[] events=type.GetEvents();
}
}
(4) 几种获取type对象的方法
(5) 设置反射类型的成员
反射类型的成员就是反射层次模型中最下面的一层数据。我们可以通过type对象的GetMembers 方法取得一个类型的成员。如果我们使用的是不带参数的GetMembers(),它只返回该类型的公共定义的静态变量和实例成员,我们也可以通过使用带参数的GetMembers()通过参数设置来返回指定的类型成员。system.reflection.Bindingflags 枚举类型的详细说明。
BindingFlags bf=bingdingFlags.DeclaredOnly|bingdingFlags.Nonpublic|BingdingFlags.Public;foreach (MemberInfo mi int t.getmembers(bf))
{
writeline(mi.membertype)
}
(6) 使用反射创建类型的实例
通过反射可以获取程序集的类型,我们就可以根据获得的程序集类型来创建该类型的新实例,我们可以通过下面的几个方法实现:
1)System.Activator 的CreateInstance方法。该方法返回新对象的引用。2)System.Activator 的createInstanceFrom 与上一个方法类似,不过需要指定类型及其程序集
3)System.Appdomain 的方法:CreateInstance(),CreateInstanceAndUnwrap,CreateInstranceFrom和CreateInstraceFromAndUnwrap
4)System.type的InvokeMember实例方法:这个方法返回一个与传入参数相符的构造函数,并构造该类型。
5)System.reflection.Constructinfo 的Invoke实例方法
(7) 反射类型的接口
如果你想要获得一个类型继承的所有接口集合,可以调用Type的FindInterfaces() GetInterface()或者GetInterfaces()。所有这些方法只能返回该类型直接继承的接口,他们不会返回从一个接口继承下来的接口。要想返回接口的基础接口必须再次调用上述方法。
(8) 不到不得以的时候,请尽量避免使用反射
使用反射来调用类型或者触发方法,或者访问一个字段或者属性时,需要做更多的工作:校验参数,检查权限等等,所以速度是非常慢的。所以尽量不要使用反射进行编程,对于打算编写一个动态构造类型的应用程序,可以采取以下的几种方式进行代替:
1)通过类的继承关系。让该类型从一个编译时可知的基础类型派生出来,在运行时生成该类型的一个实例,将对其的引用放到其基础类型的一个变量中,然后调用该基础类型的虚方法。
2)通过接口实现。在运行时,构建该类型的一个实例,将对其的引用放到其接口类型的一个变量中,然后调用该接口定义的虚方法。
3)通过委托实现。让该类型实现一个方法,其名称和原型都与一个在编译时就已知的委托相符。在运行时先构造该类型的实例,然后在用该方法的对象及名称构造出该委托的实例,接着通过委托调用你想要的方法。这个方法相对与前面两个方法所作的工作要多一些,效率更低一些。