MSDN上给出的例子十分复杂,网上的帖子则一般都说很简单,那就看看网上比较普遍的说法:
01.
“反射”其实就是利用程序集的元数据信息。
02.
03.
反射可以有很多方法,编写程序时请先导入 System.Reflection 命名空间,假设你要反射一个 DLL 中的类,并且没有引用它(即未知的类型):
04.
Assembly assembly = Assembly.LoadFile(
"程序集路径,不能是相对路径"
);
// 加载程序集(EXE 或 DLL)
05.
object
obj = assembly.CreateInstance(
"类的完全限定名(即包括命名空间)"
);
// 创建类的实例
06.
07.
若要反射当前项目中的类可以为:
08.
09.
Assembly assembly = Assembly.GetExecutingAssembly();
// 获取当前程序集
10.
object
obj = assembly.CreateInstance(
"类的完全限定名(即包括命名空间)"
);
// 创建类的实例,返回为 object 类型,需要强制类型转换
11.
12.
也可以为:
13.
Type type = Type.GetType(
"类的完全限定名"
);
14.
object
obj = type.Assembly.CreateInstance(type);
15.
16.
反射创建类的实例
因为这段描述在很多地方都有看到,笔者也不知道原始出处,所以这里就给出笔者第一次看到的地方:http://hi.baidu.com/rayord/item/92e58ddb0d34c13de3108fbb
上述描述中提到的三种方法其实都是大同小异的,核心就是通过System.Reflection.Assembly 类型的CreateInstance方法创建实例。
关于System.Reflection.Assembly 类可以直接在MSDN上查询详细信息http://msdn.microsoft.com/zh-cn/library/system.reflection.assembly(v=vs.110).aspx
那么简单的解释一下这种方法的原理:
1.找到要实例化的类所在的程序集,并将之实例为System.Reflection.Assembly 类的对象
2.利用System.Reflection.Assembly 类提供的CreateInstance方法,创建类的对象
看起来确实很简单,只是这种方法真的好用么?
笔者进行了测试以说明:
第一次测试,创建一个简单的自定义类型对象
首先创建一个类:
01.
class
Test
02.
{
03.
private
string
_strId;
04.
public
string
ID
05.
{
06.
get
{
return
_strId; }
07.
set
{ _strId = value; }
08.
}
09.
10.
public
Test()
11.
{
12.
}
13.
}
然后在主函数中加入代码:
Assembly assembly = Assembly.GetExecutingAssembly(); // 获取当前程序集
object obj = assembly.CreateInstance("ReflectionTest.Test"); //类的完全限定名(即包括命名空间)
调试结果:显示obj对象的确不为空,证明这种方法可行。
第二次测试,加深难度,测试类的构造函数需要传递参数
首先修改Test类,将其构造函数改为:
public Test(string str)
{
_strId = str;
}
调试结果:直接抛出异常:未找到类型“ReflectionTest.Test”上的构造函数。这是因为CreateInstance方法默认情况下是通过找无参数的构造函数去创建对象的,现在找不到当然会出错,实时上CreateInstance方法提供了3中签名,其中有CreateInstance(String, Boolean, BindingFlags, Binder, Object [], CultureInfo, Object []) 就可以满足这种情况:
修改主函数如下:
1.
Assembly assembly = Assembly.GetExecutingAssembly();
// 获取当前程序集
2.
//object obj = assembly.CreateInstance("ReflectionTest.Test"); //类的完全限定名(即包括命名空间)
3.
object
[] parameters =
new
object
[1];
4.
parameters[0] =
"test string"
;
5.
object
obj = assembly.CreateInstance(
"ReflectionTest.Test"
,
true
,System.Reflection.BindingFlags.Default,
null
,parameters,
null
,
null
);
// 创建类的实例
调试结果:正常,并且对象中变量值也是正确的,但是这离笔者的需求还差很远。继续
第三次测试,继续加深难度,创建string的对象
首先知道string是System.String的别名,所以要创建的是System.String的对象,而System.String在mscorlib.dll中,所以需要将mscorlib.dll实例为System.Reflection.Assembly的对象,这里利用System.Type类型的属性Assembly来实现功能。
System.String的构造函数有很多种,本文中笔者就不墨迹了,采用String( Char []) 。
最终将主函数中代码改为:
1.
Type type = Type.GetType(
"System.String"
);
2.
object
[] parameters =
new
object
[1];
3.
char
[] lpChar = {
't'
,
'e'
,
's'
,
't'
};
4.
parameters[0] = lpChar;
5.
6.
object
obj = type.Assembly.CreateInstance(
"ReflectionTest.Test"
,
true
,System.Reflection.BindingFlags.Default,
null
,parameters,
null
,
null
);
// 创建类的实例
调试结果:对象为空,失败了,事实上这种方法还有个问题,如将Test类构造函数修改为
1.
public
Test(
string
str)
2.
{
3.
ID = str;
//属性赋值
4.
}
调试结果:对象创建成功,但是变量为空
以上问题详细原因笔者现在也无法解释,正在查找相关资料。
解决方案
采用System.Activator 类的CreateInstance方法。
最后见代码:
1.
Type type = Type.GetType(
"System.String"
);
2.
object
[] parameters =
new
object
[1];
3.
char
[] lpCh = {
't'
,
'e'
,
's'
,
't'
};
4.
parameters[0] = lpCh;
5.
6.
object
obj = Activator.CreateInstance(type, parameters);
调试结果:对象创建成功,且变量值正常
结论
采用System.Activator 类的CreateInstance方法,要比System.Reflection.Assembly的CreateInstance简单有效很多。有兴趣的朋友可以仔细看看。