反射是一个强大的工具,它使得我们可以编写更为动态的软件,通过反射,一个应用程序可以通过添加一些“在应用程序部署时还不存在的”新组件,来完成新功能的升级,这是反射最大的作用。
反射也是一把双刃剑,它在带来便利的同时,也引入了复杂性,从而使得发生问题的概率也大大增加。当我们使用反射时,绕过了C#类型安全,Invoke方法接收的参数和返回值的类型都是System.Object,我们必须确保在运行时使用的是正确的类型。因此,虽然反射使得构建动态程序变得容易了,但是程序出现问题的可能性也变更多了,我们不应该过度使用反射。
我们在使用反射时,通常会有以下三种情况:创建对象实例、调用对象方法、访问对象的属性。
首先,我们来看一下如何创建对象实例,在获得对象的类型后,我们可以根据类型的名称创建一个ConstructInfo对象,然后调用该对象的Invoke方法,得到一个指定类型的对象。来看下面的代码。
![ContractedBlock.gif](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
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 }
然后,我们来看一下如何调用对象的方法:可以通过调用GetMember方法或者GetMembers方法来获得MethodInfo对象或数组,然后调用MethodInfo对象的Invoke方法。来看下面的代码。
![ContractedBlock.gif](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
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方法得到指定属性的值。来看下面的代码。
![ContractedBlock.gif](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
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 }
只有当调用目标不能清晰的使用接口来表达时,我们才应该使用反射。
综上,当我们可以使用接口来描述我们期望调用的方法或者属性时,我们将得到一个更为清晰、更具可维护性的系统。反射时一个很强大的晚绑定机制,但是在某些情况下,我们使用接口、委托或者工厂模式可以得到更具维护性的系统。