zoukankan      html  css  js  c++  java
  • C#利用反射动态创建对象 带参数的构造函数和String类型 (转载)

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

    “反射”其实就是利用程序集的元数据信息。 
    
    反射可以有很多方法,编写程序时请先导入 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.

    关于System.Reflection.

    那么简单的解释一下这种方法的原理:

    1.找到要实例化的类所在的程序集,并将之实例为System.Reflection.

    2.利用System.Reflection.

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

    笔者进行了测试以说明:

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

    首先创建一个类:

    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.

    System.String的构造函数有很多种,本文中笔者就不墨迹了,采用String(

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

    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;//属性赋值
    }

    调试结果:对象创建成功,但是变量为空

    以上问题详细原因笔者现在也无法解释,正在查找相关资料。

    解决方案

    采用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简单有效很多。有兴趣的朋友可以仔细看看。

    补充知识点

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

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

    public class MyClassObject
    {
    }

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

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

    然后我在项目ConsoleApplication2中使用:

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

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

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

  • 相关阅读:
    U-Boot新手入门
    安装交叉编译工具
    Makefile 工程管理
    gcc基本用法
    poj 3264 Balanced Lineup
    hdoj 1166 敌兵布阵
    poj 1363 Rails
    poj 1028 Web Navigation
    zoj 3621 Factorial Problem in Base K
    poj1861最小生成树
  • 原文地址:https://www.cnblogs.com/OpenCoder/p/6653984.html
Copyright © 2011-2022 走看看