反射是相当强大的一个机制,它允许在运行时发现并使用编译时还补了解的类型或成员。但是,它有下面两个缺点。
1,反射会造成编译时无法保证类型类型安全性。由于反射要严重依赖字符串,所以会丧失编译时的类型安全性。
2,反射速度慢。使用反射时,类型或成员的名称在编译时未知;要用字符串名称标识每个类型及其成员,以便在运行时发现他们。也就是说,使用System.Reflection命名空间中的类型扫描程序集的元数据时,反射要不断地执行字符串搜索。通常,字符串搜索执行的是不区分大小写的比较,这会进一步影响速度。

使用反射调用一个成员时,也会对性能产生影响。用反射调用一个方法时,首先必须将实参打包成一个数组;在内部,反射必须将这些实参包到线程栈上。此外在调用方法前,CLR必须检查实参具有正确的数据类型。最后CLR必须确保调用者有正确的安全权限来访问被调用的成员。

基于上述所有原因,最好避免利用反射来访问字段或者调用方法/属性。如果要写一个应用程序来动态发现和构造类型实例,应采取以下两种技术之一。

1,让类型从一个编译时已知的基类型派生。在运行时,构造派生类型的一个实例,将对它的引用放到基类型的一个变量中(利用转型),再调用基类型定义的虚方法。

2,让类型实现一个编译时已知的接口。在运行时,构造类型的一个实例,将对它的引用放到接口类型的一个变量中(利用转型),在调用接口定义的方法。

在这两种技术中,我个人更喜欢使用接口技术而非基类技术,因为基类技术不允许开发人员选择在一个特定情况下工作得最好的基类。不过,在需要版本控制的情形中,基类技术显得更合适一些,因为随时都能向基类型添加一个成员,派生类会直接继承它。相反,要向接口添加一个成员,实现该接口的所有类型都得修改它们的代码并重新编译。

在使用这两种技术时,强烈建议在接口或基类型自己的程序集中定义它们。这有助于缓解版本控制问题。