LOGO OA教程 ERP教程 模切知识交流 PMS教程 CRM教程 开发文档 其他文档  
 
网站管理员

C#利用反射动态创建对象 带参数的构造函数和String类型

admin
2017年4月5日 0:36 本文热度 6220
最近笔者有一个想法需要利用反射动态创建对象(如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对象的确不为空,证明这种方法可行。

第二次测试,加深难度,测试类的构造函数需要传递参数
首先修改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简单有效很多。有兴趣的朋友可以仔细看看。


该文章在 2017/4/5 0:36:30 编辑过
关键字查询
相关文章
正在查询...
点晴ERP是一款针对中小制造业的专业生产管理软件系统,系统成熟度和易用性得到了国内大量中小企业的青睐。
点晴PMS码头管理系统主要针对港口码头集装箱与散货日常运作、调度、堆场、车队、财务费用、相关报表等业务管理,结合码头的业务特点,围绕调度、堆场作业而开发的。集技术的先进性、管理的有效性于一体,是物流码头及其他港口类企业的高效ERP管理信息系统。
点晴WMS仓储管理系统提供了货物产品管理,销售管理,采购管理,仓储管理,仓库管理,保质期管理,货位管理,库位管理,生产管理,WMS管理系统,标签打印,条形码,二维码管理,批号管理软件。
点晴免费OA是一款软件和通用服务都免费,不限功能、不限时间、不限用户的免费OA协同办公管理系统。
Copyright 2010-2024 ClickSun All Rights Reserved