C#实例化类型

206 阅读3分钟

通过前面的学习,我们大概了解到 Assembly、PropertyInfo、FieldInfo、ConstructorInfo、MethodInfo、ParameterInfo、EventInfo、MemberInfo 的存在和输出信息。

从本篇文章,将开始通过反射实例化类型,进行一系列的反射操作实践。

本篇文章,主要讲述实例化类型、实例化委托。

1,实例化类型

从类型(Type)创建实例对象的方式,有两种

  • Activator.CreateInstance() 方法 ,通过 类型 Type
  • ConstructorInfo.Invoke(),通过 构造函数 ConstructorInfo

实例化一个类型时,首先考虑如何处置该类型的构造函数。

1.1 Activator.CreateInstance()

首先,在 Microsoft Docs 中,这么定义:

使用与指定参数匹配程度最高的构造函数创建指定类型的实例。

这是什么意思呢?

我们来看一下 Activator.CreateInstance() 最常用的两个个重载。

object? CreateInstance(Type type);
object? CreateInstance(Type type, params object[] args);

args 就是实例化类型时,给构造函数传递的参数。因为使用的是 object ,最终实例化是使用到的 构造函数 是 区配程度 最高的。

1.2 ConstructorInfo.Invoke()

ConstructorInfo.Invoke() 调用构造函数的限制性比Activator.CreateInstance() 高,并且是严格对应的。

1.1.4 中,故意出错的代码中,可以看到因为 null 时,有多个构造函数符合条件而导致程序报错。

使用 ConstructorInfo.Invoke() 创建实例进行测试。

    public class MyClass
    {
        public MyClass(string a = null) { Console.WriteLine(6666); }
        public MyClass(StringBuilder a = null) { }
    }
    class Program
    {
        static void Main(string[] args)
        {
            // 通过唯一性获取构造函数
            // 通过参数类型和数量,获取到唯一的构造函数
            ConstructorInfo conStruct = typeof(MyClass).GetConstructor(new Type[] { typeof(string) });

            // 传输参数值并且进行实例化
            object objA = conStruct.Invoke(new object[] { null });

            Console.ReadKey();
        }
    }

使用 typeof(MyClass).GetConstructor(new Type[] { typeof(string) }); 获取到类型的构造函数,然后使用 ConstructorInfo.Invoke() 实例化。

上面 GetConstructor() 的方法,重载定义如下

public ConstructorInfo? GetConstructor(Type[] types);

通过什么的方法,可以使用 public 构造函数实例化一个类型,如果想调用非 public 的构造函数呢?

可以使用 BindingFlags,这些后面再慢慢学习。

2,实例化委托

使用 Delegate.CreateDelegate() 方法实例化一个委托,使用 Delegate.DynamicInvoke() 调用委托并且传递参数。

使用形式

CreateDelegate(Type, Object, MethodInfo)

Type 是此委托类型,Object 、MethodInfo 是实例类型、方法。

有两种情况,一种是实例方法、一种是静态方法。

我们创建一个委托以及类型

    delegate int Test(int a, int b);
    public class MyClass
    {
        public  int A(int a, int b)
        {
            Console.WriteLine("A");
            return a + b;
        }
        public static int B(int a, int b)
        {
            Console.WriteLine("B");
            return a - b;
        }
    }

Main() 中 实验代码如下

            // 绑定实例方法
            Delegate d1 = Delegate.CreateDelegate(typeof(Test), new MyClass(), "A");

            // 绑定静态方法
            Delegate d2 = Delegate.CreateDelegate(typeof(Test), typeof(MyClass), "B");

            Console.WriteLine(d1.DynamicInvoke(333,333));
            Console.WriteLine(d2.DynamicInvoke(999,333));

            Console.ReadKey();

输出

A
666
B
666

3,实例化泛型类型

3.1 实例化泛型

实例化一个泛型类型时,可以按照实例化普通类型过程操作

            // 正常
            Type type = typeof(List<int>);
            object obj = Activator.CreateInstance(type);

            // 下面的会报错
            Type _type = typeof(List<>);
            object _obj = Activator.CreateInstance(_type);

使用 Activator.CreateInstance 方法实例化一个泛型类型时,必须是 已绑定类型参数 的泛型 Type。

List<int> 已绑定 √; List<> 未绑定 ×。

另外,通过 ConstructorInfo.Invoke() 实例化也是一样的。

    public class MyClass<T>
    {
        public MyClass(T a)
        {
            Console.WriteLine(a);
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            // 正常
            ConstructorInfo type = typeof(MyClass<int>).GetConstructor(new Type[] { typeof(int) });
            object obj = type.Invoke(new object[] { 666 });

            Console.ReadKey();
        }
    }

3.2 构造封闭泛型类型以及反转

3.2.1 构造封闭构造函数

有时候,传递过来的恰恰是 List<> 呢?

使用 Type.MakeGenericType(Type)

我们可以这样多一步,将未绑定类型参数的泛型 Type,转为封闭的 泛型 Type。

            Type type = typeof(List<>);

            // 构建泛型 Type
            Type _type = type.MakeGenericType(typeof(int));
            object _obj = Activator.CreateInstance(_type);

3.2.2 去除泛型类型的参数类型绑定

使用 Type.GetGenericTypeDefinition() 方法可以去除一个已绑定参数类型的泛型类型的参数类型。

            Type type = typeof(List<int>);
            Console.WriteLine(type.FullName);
            // 构建泛型 Type
            Type _type = type.GetGenericTypeDefinition();
            Console.WriteLine(_type.FullName);

输出

System.Collections.Generic.List`1[[System.Int32, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]
System.Collections.Generic.List`1

List<int> 变成了 List<>

3.2.3 实践一下

上面介绍了泛型类型的实例化和两个关于参数类型的使用,下面来实践一下

        static void Main(string[] args)
        {
            Type typeA = typeof(Console);
            Type typeB = typeof(List<>);
            Type typeC = typeof(List<int>);

            去除泛型类型绑定的参数类型(typeA);
            去除泛型类型绑定的参数类型(typeB);
            去除泛型类型绑定的参数类型(typeC);
            Console.ReadKey();
        }

        /// <summary>
        ///  将 List<T> 转为 List<>
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public static (bool, Type) 去除泛型类型绑定的参数类型(Type type)
        {
            // 检查是否泛型类型
            if (type.IsGenericType == false)
            {
                Console.WriteLine("此类型不是泛型类型");
                return (false, type);
            }

            // 检查是否是未绑定参数类型的泛型类型
            if (type.IsGenericTypeDefinition)
            {
                Console.WriteLine("本来就不需要处理");
                return (true, type);
            }

            Type _type = type.GetGenericTypeDefinition();
            Console.WriteLine("处理完毕");
            return (true, _type);
        }
    }

原文链接:reflect.whuanle.cn/4.to4.html