zoukankan      html  css  js  c++  java
  • 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 }
        由于反射带来了弱类型问题,这样在如何动态的创建对象方面,我们可以寻找其他解决方案,我们可以使用接口来在运行时指定对象的类型。

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

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

  • 相关阅读:
    Eclipse中的快捷键
    xml文件头文件生成策略以及导入约束条件
    HTTP协议状态代码和错误状态含义的解释
    水了一个前端面试 记下问的东西
    整理的一些PHP面试题目
    Magic Index 寻找数组中A[i]=i的位置(原题转自微信号待字闺中)
    【经典算法】寻找最长01字串(转自待字闺中)
    PHP中不用第三个变量交换两个变量的值
    已知一个数组a[N]来构造数组b[N]的有趣算法题
    MySQL安装后默认自带数据库的作用
  • 原文地址:https://www.cnblogs.com/wing011203/p/1675300.html
Copyright © 2011-2022 走看看