最近笔者有一个想法须要利用反射动态建立对象(如string,int,float,bool,以及自定义类等)来实现,一直感受反射用很差,特别是当构造函数带参数的时候。
MSDN上给出的例子十分复杂,网上的帖子则通常都说很简单,那就看看网上比较广泛的说法:ide
“反射”其实就是利用程序集的元数据信息。 反射能够有不少方法,编写程序时请先导入 System.Reflection 命名空间,假设你要反射一个 DLL 中的类,而且没有引用它(即未知的类型): Assembly assembly = Assembly.LoadFile("程序集路径,不能是相对路径"); // 加载程序集(EXE 或 DLL) object obj = assembly.CreateInstance("类的彻底限定名(即包括命名空间)"); // 建立类的实例 若要反射当前项目中的类能够为: Assembly assembly = Assembly.GetExecutingAssembly(); // 获取当前程序集 object obj = assembly.CreateInstance("类的彻底限定名(即包括命名空间)"); // 建立类的实例,返回为 object 类型,须要强制类型转换 也能够为: Type type = Type.GetType("类的彻底限定名"); object obj = type.Assembly.CreateInstance(type);
由于这段描述在不少地方都有看到,笔者也不知道原始出处,因此这里就给出笔者第一次看到的地方: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).aspxspa
那么简单的解释一下这种方法的原理:.net
1.找到要实例化的类所在的程序集,并将之实例为System.Reflection.Assembly 类的对象3d
2.利用System.Reflection.Assembly 类提供的CreateInstance方法,建立类的对象调试
看起来确实很简单,只是这种方法真的好用么?code
笔者进行了测试以说明:htm
第一次测试,建立一个简单的自定义类型对象对象
首先建立一个类:
class Test { private string _strId; public string ID { get { return _strId; } set { _strId = value; } } public Test() { } }
而后在主函数中加入代码:
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 []) 就能够知足这种状况:
修改主函数以下:
Assembly assembly = Assembly.GetExecutingAssembly(); // 获取当前程序集 //object obj = assembly.CreateInstance("ReflectionTest.Test"); //类的彻底限定名(即包括命名空间) object[] parameters = new object[1]; parameters[0] = "test string"; 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 []) 。
最终将主函数中代码改成:
Type type = Type.GetType("System.String"); object[] parameters = new object[1]; char[] lpChar = { 't','e','s','t' }; parameters[0] = lpChar; object obj = type.Assembly.CreateInstance("ReflectionTest.Test",true,System.Reflection.BindingFlags.Default,null,parameters,null,null);// 建立类的实例
调试结果:对象为空,失败了,事实上这种方法还有个问题,如将Test类构造函数修改成
public Test(string str) { ID = str;//属性赋值 }
调试结果:对象建立成功,可是变量为空
以上问题详细缘由笔者如今也没法解释,正在查找相关资料。
解决方案
最后笔者在《C#中使用反射获取结构体实例及思路》一文中找到了解决方案
采用System.Activator 类的CreateInstance方法。
最后见代码:
Type type = Type.GetType("System.String"); object[] parameters = new object[1]; char[] lpCh = { 't', 'e', 's', 't' }; parameters[0] = lpCh; object obj = Activator.CreateInstance(type, parameters);
调试结果:对象建立成功,且变量值正常
结论
采用System.Activator 类的CreateInstance方法,要比System.Reflection.Assembly的CreateInstance简单有效不少。有兴趣的朋友能够仔细看看。详细资料http://msdn.microsoft.com/zh-cn/library/system.activator(v=vs.110).aspx