最近笔者有一个想法需要利用反射动态创建对象(如string,int,float,bool,以及自定义类等)来实现,一直感觉反射用不好,特别是当构造函数带参数的时候。
MSDN上给出的例子十分复杂,网上的帖子则一般都说很简单,那就看看网上比较普遍的说法:

  1. “反射”其实就是利用程序集的元数据信息。
  2.  
  3. 反射可以有很多方法,编写程序时请先导入 System.Reflection 命名空间,假设你要反射一个 DLL 中的类,并且没有引用它(即未知的类型):
  4. Assembly assembly = Assembly.LoadFile("程序集路径,不能是相对路径"); // 加载程序集(EXE 或 DLL)
  5. object obj = assembly.CreateInstance("类的完全限定名(即包括命名空间)"); // 创建类的实例
  6.  
  7. 若要反射当前项目中的类可以为:
  8.  
  9. 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方法,创建类的对象

看起来确实很简单,只是这种方法真的好用么?

笔者进行了测试以说明:

第一次测试,创建一个简单的自定义类型对象

首先创建一个类:

  1. class Test
  2. {
  3. private string _strId;
  4. public string ID
  5. {
  6. get { return _strId; }
  7. set { _strId = value; }
  8. }
  9.  
  10. public Test()
  11. {
  12. }
  13. }

然后在主函数中加入代码:

Assembly assembly = Assembly.GetExecutingAssembly(); // 获取当前程序集 object obj = assembly.CreateInstance("ReflectionTest.Test"); //类的完全限定名(即包括命名空间)

调试结果:显示obj对象的确不为空,证明这种方法可行。

第二次测试,加深难度,测试类的构造函数需要传递参数

首先修改Test类,将其构造函数改为:

  1. public Test(string str)
  2. {
  3. _strId = str;
  4. }

调试结果:直接抛出异常:未找到类型“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[];
  4. parameters[] = "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( array<Char []()>[]) 。

最终将主函数中代码改为:

  1. Type type = Type.GetType("System.String");
  2. object[] parameters = new object[];
  3. char[] lpChar = { 't','e','s','t' };
  4. parameters[] = 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[];
  3. char[] lpCh = { 't', 'e', 's', 't' };
  4. parameters[] = lpCh;
  5.  
  6. object obj = Activator.CreateInstance(type, parameters);

调试结果:对象创建成功,且变量值正常

结论

采用System.Activator 类的CreateInstance方法,要比System.Reflection.Assembly的CreateInstance简单有效很多。有兴趣的朋友可以仔细看看。

补充知识点

使用Type.GetType(string typeName)方法获取类型时,参数typeName中声明的程序集没有必要在当前项目中引用,只要放在生成项目的bin目录下即可:

比如下面我构造了一个类库项目MyClass包含类MyClassObject

  1. public class MyClassObject
  2. {
  3. }

我在项目ConsoleApplication2中并没有引用类库项目MyClass的程序集,如下图所示

但是我手动将类库项目MyClass的DLL文件复制到了项目ConsoleApplication2的bin目录下:

然后我在项目ConsoleApplication2中使用:

  1. Type myType = Type.GetType("MyClass.MyClassObject,MyClass");

是可以成功获取到MyClassObject的Type类型的:

这说明C#中使用反射,在项目中不引用程序集也可以构造程序集中的类,只要将程序集文件(DLL文件)放在和项目所生成文件相同的文件夹(一般是bin目录)下即可。

C#利用反射动态创建对象 带参数的构造函数和String类型 (转载)的更多相关文章

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

    C# 利用反射动态创建对象——带参数的构造函数和String类型 最近笔者有一个想法需要利用反射动态创建对象(如string,int,float,bool,以及自定义类等)来实现,一直感觉反射用不好, ...

  2. C# 利用反射动态创建对象[摘录]

    摘自:http://hi.baidu.com/yangyuhang/blog/item/f12ea90e13f214e336d12250.html 在VS.Net中,有很多种方法动态调用对象的构造函数 ...

  3. 【转】C# 利用反射动态创建对象

    http://www.cnblogs.com/Jan_Dai/archive/2010/11/09/1872812.html Activator.CreateInstance(Type.GetType ...

  4. C#回顾 - 8.利用反射动态创建对象

    拿微信消息返回的示例数据实验 var data = "<xml><ToUserName><![CDATA[toUser]]></ToUserName ...

  5. C# 利用反射动态加载dll

    笔者遇到的一个问题,dll文件在客户端可以加载成功,在web端引用程序报错.解决方法:利用反射动态加载dll 头部引用加: using System.Reflection; 主要代码: Assembl ...

  6. C# 知识点笔记:IEnumerable<>的使用,利用反射动态调用方法

    IEnumerable<T>的使用 创建一个IEnumerable对象 List<string> fruits = new List<string> { " ...

  7. .Net Core利用反射动态加载类库的方法(解决类库不包含Nuget依赖包的问题)

    在.Net Framework时代,生成类库只需将类库项目编译好,然后拷贝到其他项目,即可引用或动态加载,相对来说,比较简单.但到了.Net Core时代,动态加载第三方类库,则稍微麻烦一些. 一.类 ...

  8. C#的泛型的类型参数可以有带参数的构造函数的约束方式吗?

    Review后看到标题让我十分羞愧自己语文功底太差,估计...请见谅......我还特地把这句写回开头了...... 问题 前天遇到的一个问题,所以在MSDN发了个问,刚也丰富了下问题,关于泛型的. ...

  9. mfc 带参数的构造函数

    知识点 默认的构造函数 带参数的构造函数 重载构造函数 一.默认的构造函数 二.带参数的构造函数 三.重载构造函数 class Tdate { public: int year;//年 int mon ...

随机推荐

  1. luogu P2801 教主的魔法

    题目描述 教主最近学会了一种神奇的魔法,能够使人长高.于是他准备演示给XMYZ信息组每个英雄看.于是N个英雄们又一次聚集在了一起,这次他们排成了一列,被编号为1.2.…….N. 每个人的身高一开始都是 ...

  2. CSS属性之margin

    0.对自身可视宽度的影响 1>改变处于标准文档流中,未设置width值的block元素的可视宽度 在标准文档流中,对于没有设置宽度的block元素,当其具有内容或者设置高度后,其自身宽度为父元素 ...

  3. PHP中使用Jpgraph生成统计图

    Jpgraph是PHP图表类库,可以生成折线图.柱状图.大饼图等等统计图.如果你想使用PHP生成统计图来统计数据,使用它再方便不过啦. 如果说你要亲自使用GD库来写的话,那我只能膜拜大神啦(我不会哈哈 ...

  4. position布局影响点击事件以及冒泡获取事件目标

    在编写功能时总是会出现很多意想不到的问题,现在就讲讲我遇到的两个问题,通过举一个相似的例子来解说. <1> 元素互相独立,不存在包含于被包含 选择城市的按钮,为它绑定点击事件,点击后就弹出 ...

  5. 在IE、fixfox、chrome等浏览器中ajax提交成功后,打开新标签页面被浏览器拦截问题[转]

    如题: 在项目中要在当前页面中,再新开一个页面, 新开页面的地址是ajax请求后返回的url --------- 试了,浏览器提示组织弹窗..... 网上找,找到了一个处理方式,思路是 1. 先打开一 ...

  6. Wasserstein GAN最新进展:从weight clipping到gradient penalty,更加先进的Lipschitz限制手法

    前段时间,Wasserstein GAN以其精巧的理论分析.简单至极的算法实现.出色的实验效果,在GAN研究圈内掀起了一阵热潮(对WGAN不熟悉的读者,可以参考我之前写的介绍文章:令人拍案叫绝的Was ...

  7. HiJson工具 && 火狐浏览器中的jsonHandle插件(以及乱码问题的解决)-->来转换json串的格式

    原文:http://blog.csdn.net/cjm2484836553/article/details/72453907 版权声明:本文为博主原创文章,未经博主允许不得转载.   目录(?)[-] ...

  8. How do I use the API correctly

    1:打开帮助文档2:点击显示,找到索引,看到输入框3:你要学习什么内容,你就在框框里面输入什么内容 举例:Random4:看包 java.lang包下的类在使用的时候是不需要导包的5:看类的描述 Ra ...

  9. Java 快速入门-06-JDK 目录文件说明

    Java 快速入门-06-JDK 目录文件说明 JDK:开发环境,搞技术的人或者应用服务器使用 JRE:运行环境,如浏览器插件或者Swing界面的客户端等最终用户需要使用 JDK自含一个JRE,并依赖 ...

  10. MySQL两个表联合查询并按时间排序

    有一张资金记录表,一张金币记录表,想以时间为单位,降序合并排列他们之间的信息,查询SQL如下: select * from (select * from t_money_logs union sele ...