zoukankan      html  css  js  c++  java
  • 反射动态创建类型示例

    .NET中除了构造函数外,还有多种方式可以创建类型的实例。下面总结了几种常见的通过反射创建类型实例的方法。

    假设我们需要创建有这样一个类型的实例:

    复制代码
    public class Employee
    {
        public String Name { get; set; }
        public Employee(String name)
        {
            Name = name;
        }
    
        public Employee ()
        {
        }
    
        public void Say(String greeting)
        {
            Console.WriteLine(String.Format("Employee {0} say: {1} ", Name, greeting));
        }
    }
    复制代码

     

    System.Activator

    System.Activator类中提供了三组静态方法来创建类型的实例,每组方法均提供多个重载,适用不同的场景。个别重载方法返回ObjectHandle对象,需要unwrap后才能获取对象实例。

    CreateInstance

    CreateInstanceFrom

    CreateComInstanceFrom

    以下实例代码演示了如何使用上述方法创建对象实例:

    复制代码
    // 使用无参构造函数
    var employee = (Employee)Activator.CreateInstance(typeof(Employee));
    employee = Activator.CreateInstance<Employee>();
    employee.Say("CreateInstance with default ctor");
    
    // 使用有参构造函数
    employee=(Employee)Activator.CreateInstance(typeof(Employee), new object[] { "David" });
    employee.Say("CreateInstance with ctor with args");
                
    string assembly ="Test, Version=1.0.4562.31232, Culture=neutral, PublicKeyToken=null";
    string type="Test.Tests.Employee";
    var employeeHandle = Activator.CreateInstance(
            assembly,
            type);
    employee = (Employee)employeeHandle.Unwrap();
    employee.Say("CreateInstance and unwrap.");
                
    string assemblyPath=@"E:\StudyProj\ShartDev\Test\Test\bin\Debug\Test.exe";
    employeeHandle = Activator.CreateInstanceFrom(
            assemblyPath,
            type);
    employee = (Employee)employeeHandle.Unwrap();
    employee.Say("CreateInstanceFrom and unwrap.");
    复制代码

     

    System.AppDomain

    与Activator类似,AppDomain提供了4组实例方法创建类型的实例。除了创建对象外,还指定了对象所归属的AppDomain。

    CreateInstance

    CreateInstanceAndUnwrap

    CreateInstanceFrom

    CreateInstanceFromAndUnwrap

     

    System.Type

    使用Type.InvokerMember可以调用类型的方法、属性。自然也可以通过调用类型的构造函数来创建一个类型的实例。

    复制代码
    //直接调用无参构造函数
    Object obj = typeof(Employee).InvokeMember(null, BindingFlags.CreateInstance, null, null, null);
    Employee employee =obj as Employee;
    employee.Say("InvokeMember default ctor");
    
    // 使用带参数的构造函数
    obj = typeof(Employee).InvokeMember(null, BindingFlags.CreateInstance, null, null, new object[] { "david" });
    employee = obj as Employee;
    ((Employee)obj).Say("InvokeMember ctor with argument");
    复制代码

     

    System.Reflection.ConstructorInfo

    除了直接适用InvokerMember调用构造函数外,还可以先以反射的方式获取构造函数对应的MemberInfo,具体类型为ConstructorInfo,然后使用其Invoke方法。

    复制代码
    // 首先获取构造函数,然后再Invoke
    ConstructorInfo ctor = typeof(Employee).GetConstructor(new Type[] { typeof(string) });
    var emp = (Employee)ctor.Invoke(new object[]{"david"});
    emp.Say("ConstructorInfo");
    复制代码

    本来一步可以完成的操作,分两边走完的确是麻烦了些,但好处在于获取ConstructorInfo之后,后续多次调用Invoke时,避免重复绑定,可以提高效率,适用于需要重复多次使用同一个构造函数创建实例的场景。反射的绑定过程是按照字符串比较的方式在程序集元数据中查找匹配的成员,速度较慢。

     

    数组,委托和泛型类型的创建

    Array

    Array类型可以使用静态方法Array.CreateInstance方法创建。Array类还提供了其他重载方法来创建多维数组。

    var array = Array.CreateInstance(typeof(int),20);
    Console.WriteLine(array.GetType().Name+" " +array.Length);

    委托

    创建Delegate类型需要使用Delegate.CreateDelegate.

    复制代码
    MethodInfo methodInfo = typeof(CreateInstanceTest).GetMethod("StaticDoSomething",BindingFlags.Public|BindingFlags.Static);
    Delegate dele = Delegate.CreateDelegate(typeof(DoSomethingDelegate),methodInfo);
    dele.DynamicInvoke("just say hi");
    复制代码

    Generic

    创建泛型类型的实例,首先要获取对应的开放类型(Open type)的引用,然后调用Type类型的MakeGenericType方法,传入一个包含泛型参数的数组即可获取一个封闭类型(Closed Type).使用该封闭类型,调用Activator接受Type参数的某个方法既可以构造出具体的实例。

    复制代码
    Type open = typeof(Dictionary<,>);
    Type closeType = open.MakeGenericType(typeof(String),typeof(object));
    object obj = Activator.CreateInstance(closeType);
    Console.WriteLine(obj.GetType());
    复制代码

    以上即是常用的几种创建对象实例的方式,实际应用中可以根据具体场景做选择。

     

     
    分类: C#
  • 相关阅读:
    heat模板
    Leetcode812.Largest Triangle Area最大三角形面积
    Leetcode812.Largest Triangle Area最大三角形面积
    Leetcode811.Subdomain Visit Count子域名访问计数
    Leetcode811.Subdomain Visit Count子域名访问计数
    Leetcode806.Number of Lines To Write String写字符串需要的行数
    Leetcode806.Number of Lines To Write String写字符串需要的行数
    Leetcode819.Most Common Word最常见的单词
    Leetcode819.Most Common Word最常见的单词
    Leetcode783.Minimum Distance Between BST Nodes二叉搜索树结点最小距离
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/2569877.html
Copyright © 2011-2022 走看看