Effective C# Item43 : 避免过度使用反射

    反射是一个强大的工具,它使得我们可以编写更为动态的软件,通过反射,一个应用程序可以通过添加一些“在应用程序部署时还不存在的”新组件,来完成新功能的升级,这是反射最大的作用。

    反射也是一把双刃剑,它在带来便利的同时,也引入了复杂性,从而使得发生问题的概率也大大增加。当我们使用反射时,绕过了C#类型安全,Invoke方法接收的参数和返回值的类型都是System.Object,我们必须确保在运行时使用的是正确的类型。因此,虽然反射使得构建动态程序变得容易了,但是程序出现问题的可能性也变更多了,我们不应该过度使用反射。

    我们在使用反射时,通常会有以下三种情况:创建对象实例、调用对象方法、访问对象的属性。

    首先,我们来看一下如何创建对象实例,在获得对象的类型后,我们可以根据类型的名称创建一个ConstructInfo对象,然后调用该对象的Invoke方法,得到一个指定类型的对象。来看下面的代码。

代码
1 // Usage:Create a new object using reflection:
2 Type t = typeof( MyType );
3 MyType obj = NewInstance( t ) as MyType;
4
5
6 // Example factory function, based on Reflection:
7 object NewInstance( Type t )
8 {
9 // Find the default constructor:
10 ConstructorInfo ci = t.GetConstructor( new Type[ 0 ] );
11 if ( ci != null )
12 // Invoke default constructor, and return
13 // the new object.
14 return ci.Invoke( null );
15
16 // If it failed, return null.
17 return null;
18 }
    可以看出,上述代码关于是弱类型的,在编译时,是不会有任何问题的,但是,如果在运行时,NewInstance方法传入的Type并不是指定的类型,那么就会发生运行时异常,这种情况是很难提前预知的。

    然后,我们来看一下如何调用对象的方法:可以通过调用GetMember方法或者GetMembers方法来获得MethodInfo对象或数组,然后调用MethodInfo对象的Invoke方法。来看下面的代码。

代码
1 // Example usage:
2 Dispatcher.InvokeMethod( AnObject, "MyHelperFunc" );
3
4 // Dispatcher Invoke Method:
5 public void InvokeMethod ( object o, string name )
6 {
7 // Find the member functions with that name.
8 MemberInfo[] myMembers = o.GetType( ).GetMember( name );
9 foreach( MethodInfo m in myMembers )
10 {
11 // Make sure the parameter list matches:
12 if ( m.GetParameters( ).Length == 0 )
13 // Invoke:
14 m.Invoke( o, null );
15 }
16 }
    上述代码只是简单的示例,它只调用了对象的无参方法,如果想做一个可以重用的库,还需要添加对参数类型的检查。

    最后,我们来看一下如何访问对象的属性:可以通过调用GetField方法或者GetFields方法获得FiledInfo对象或者数组;可以通过调用GetProperty方法或者GetProperties方法获得PropertyInfo对象或者数组;然后调用GetValue方法得到指定属性的值。来看下面的代码。

代码
1 // Example usage:
2 object field = Dispatcher.RetrieveField ( AnObject, "MyField" );
3
4 // elsewhere in the dispatcher class:
5 public object RetrieveField ( object o, string name )
6 {
7 // Find the field.
8 FieldInfo myField = o.GetType( ).GetField( name );
9 if ( myField != null )
10 return myField.GetValue( o );
11 else
12 return null;
13 }
    由于反射带来了弱类型问题,这样在如何动态的创建对象方面,我们可以寻找其他解决方案,我们可以使用接口来在运行时指定对象的类型。

    只有当调用目标不能清晰的使用接口来表达时,我们才应该使用反射。

    综上,当我们可以使用接口来描述我们期望调用的方法或者属性时,我们将得到一个更为清晰、更具可维护性的系统。反射时一个很强大的晚绑定机制,但是在某些情况下,我们使用接口、委托或者工厂模式可以得到更具维护性的系统。

原文地址:https://www.cnblogs.com/wing011203/p/1675300.html