运行时反射
摘录于<<clr via c#>> third version
1.在编译时是不知道某个类型以及类型的实例中都含有哪些成员的,而在运行时,通过反射查看元数据信息可以获取类型,对象相关的详细信息。
2.事实上,需要使用反射类型的应用程序还是比较少的。反射类型一般应用于一些类库,这些类库需要理解类型的定义,以便提供某些丰富的功能。例如,FCL的序列化机制就是使用反射来确定一个类型中定义了哪些字段,序列化格式器随后会获取这些字段的值,并将它们写入一个字节流中,以便在网上发送、保存到文件或者复制到剪贴板。类似地,VS设计器在设计时也使用反射来确定控件被放在Web窗体或者Windows窗体上时,哪些属性应该向开发人员显示。
3.应用程序需要在运行时加载某个特定的类型或程序集以执行一些任务时,反射也显得十分有用。例如,一个应用程序可能会要求用户提供一个程序集和类型的名称,然后应用程序就可以显式地加载程序集,构建类型实例并调用类型上定义的方法了。先绑定类型,后调用方法的方式通常称为迟绑定;早绑定指的是应用程序使用的类型和方法在编译时就已经确定的绑定。
4.反射的缺点
1)由于反射使用了大量的字符串,在编译时就失去了类型安全。例如,如果调用Type.GetType("Jef")通过反射来在一个拥有称为"Jeff"的类型的程序集中查找一个称为"Jef"的类型时,代码是可以通过编译的,但在运行时会产生一个错误,因为我们不小心拼错了作为参数传递的类型名称。
2)反射的速度慢。使用反射,意味着要不断地扫描程序集的整个元数据,执行类型的字符串搜索。通常,字符串的搜索是不区分大小写的,这会使反射的速度更加慢。
3)使用反射调用成员也会影响性能。使用反射来调用方法时,必须将参数打包成一个数组,在反射内部需要解包到线程栈上。同样,CLR在调用方法之前必须检查参数是不是正确的数据类型,最后,CLR必须确保调用者有正确的安全权限来访问被调用的成员。
//基于以上所有原因,最好避免使用反射来访问类型成员。另外,如果正在编写的应用程序需要动态地发现和构建类型,我们应遵循下述两个方法中的一个:
A.让类型派生自一个在编译时已经确定的基础类型。然后在运行时构建一个该派生类型的实例,并将其引用存放在一个声明类型为其基类型的变量中(可以进行类型转换),最后调用基类型中定义的虚方法。
B.让类型实现一个在编译时已经确定的接口类型。然后在运行时构建一个该类型的实例,并将其引用存放在一个声明类型为其接口类型的变量中(可以进行类型转换),最后调用接口类型中定义的方法。
//第二种方法更通用
5.GetType()与typeof()
GetType()返回对象在运行时的类型(迟绑定),typeof()返回对象在编译时的类型(早绑定)
1 private static void SomeMethod(object o) 2 { 3 if (o.GetType() == typeof(FileInfo)) { } 4 if (o.GetType == typeof(DirectoryInfo)) { } 5 }
//代码中的if语句是做精确匹配,而不是兼容性匹配。例如第一个if语句,做的是检查对象o是不是FileInfo类型,而不是检查它是不是FileInfo的一个子类型
//一但得到了Type对象的引用,我们就可以查询该类型的许多属性,更进一步了解该类型。Type类是进行反射的入口,这个类封装了关于对象的信息,根据Type提供的属性和方法获取这个类型的一切信息(方法,字段,属性,事件,参数,构造函数等)