C#利用反射动态创建对象 带参数的构造函数和String类型
当前位置:点晴教程→知识管理交流
→『 技术文档交流 』
最近笔者有一个想法需要利用反射动态创建对象(如string,int,float,bool,以及自定义类等)来实现,一直感觉反射用不好,特别是当构造函数带参数的时候。
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对象的确不为空,证明这种方法可行。 第二次测试,加深难度,测试类的构造函数需要传递参数 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是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简单有效很多。有兴趣的朋友可以仔细看看。 该文章在 2017/4/5 0:36:30 编辑过 |
关键字查询
相关文章
正在查询... |