利用反射动态创建对象

来源:互联网 发布:ubuntu怎么挂载u盘 编辑:程序博客网 时间:2024/06/03 06:06

我们新建一个Console控制台项目,叫做Reflection4(因为本文是Part4,你也可以起别的名字)。然后,添加一个示范类,本文中将通过对这个示范类的操作来进行说明:

public class Calculator {    private int x;    private int y;    public Calculator(){       x = 0;       y = 0;    }    public Calculator(int x, int y) {       this.x = x;       this.y = y;    }}

1.使用无参数构造函数创建对象

上面这个类非常简单,它包含两个构造函数,一个是有参数的构造函数,一个是无参数的构造函数,我们先看看通过反射,使用无参数的构造函数创建对象。创建对象通常有两种方式,一种是使用Assembly的CreateInstance方法:

Assembly asm = Assembly.GetExecutingAssembly();           
Object obj = asm.CreateInstance("Reflection4.Calculator", true);
// 输出:Calculator() invoked

CreateInstance的第一个参数代表了要创建的类型实例的字符串名称,第二个参数说明是不是大小写无关(Ignore Case)。注意到CreateInstance返回的是一个Object对象,意味着如果想使用这个对象,需要进行一次类型转换。

创建对象的另一种方式是调用Activator类的静态方法CreateInstance:

ObjectHandle handler = Activator.CreateInstance(null, "Reflection4.Calculator");
Object obj = handler.Unwrap();

其中CreateInstance的第一个参数说明是程序集的名称,为null时表示当前程序集;第二个参数说明要创建的类型名称。Activator.CreateInstance返回的是一个ObjectHandle对象,必须进行一次Unwrap()才能返回Object类型,进而可以强制转换成我们需要的类型(本例中是Calculator)。ObjectHandle包含在System.Runtime.Remoting命名空间中,可见它是Remoting相关的,对于Remoting我暂时没有做太多研究,我们现在只要知道可以通过这种方式创建对象就可以了。

2.使用有参数构造函数创建对象

如果我们想通过有参数的构造函数创建对象,我们可以使用Assembly的CreateInstanc()的重载方法:

// 有参数构造函数创建对象
Assembly asm = Assembly.GetExecutingAssembly();
Object[] parameters = new Object[2];    // 定义构造函数需要的参数
parameters[0] = 3;
parameters[1] = 5;

Object obj = asm.CreateInstance("Reflection4.Calculator", true, BindingFlags.Default, null, parameters, null, null);

// 输出:Calculator(int x, int y) invoked

我们看一下CreateInstance需要提供的参数:

  1. 前两个在前一小节已经说明过了;
  2. BindingFlags在前面我们也用到过,它用于限定对类型成员的搜索。在这里指定Default,意思是不使用BingdingFlags的策略(你可以把它理解成null,但是BindingFlags是值类型,所以不可能为null,必须有一个默认值,而这个Default就是它的默认值);
  3. 接下来的参数是Binder,它封装了CreateInstance绑定对象(Calculator)的规则,我们几乎永远都会传递null进去,实际上使用的是预定义的DefaultBinder;
  4. 接下来是一个Object[]数组类型,它包含我们传递进去的参数,有参数的构造函数将会使用这些参数;
  5. 接下来的参数是一个CultureInfo类型,它包含了关于语言和文化的信息(简单点理解就是什么时候ToString("c")应该显示“¥”,什么时候应该显示“$”)。

贴一个实际使用的类

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Reflection;namespace HealCore.BasicData{    public class BasicDictionaryFactory    {        private static Assembly m_CurrentAsm;        private static string m_CurrAsmName = "HealCore.BasicData.";        static BasicDictionaryFactory()        {            m_CurrentAsm = Assembly.GetExecutingAssembly();        }        public static IBasicDictionaryBLL CreateBasicDictionaryBLL(string tableName, params object[] parameters)        {            try            {                if (parameters == null)                {                    return (IBasicDictionaryBLL)m_CurrentAsm.CreateInstance(string.Format("{0}{1}Bll", m_CurrAsmName, tableName), true);                }                else                {                    return (IBasicDictionaryBLL)m_CurrentAsm.CreateInstance(string.Format("{0}{1}Bll", m_CurrAsmName, tableName), true, BindingFlags.Default, null, parameters, null, null);                }            }            catch            {                return null;            }        }        public static object CreateModel(string tableName)        {            object objReturn = null;            try            {                objReturn = m_CurrentAsm.CreateInstance(tableName, true);            }            catch            {            }            return objReturn;        }    }}