使用Type.MakeGenericType,反射构造泛型类型

有时我们会有通过反射来动态构造泛型类型的需求,该如何实现呢?举个栗子,比如我们常常定义的泛型委托Func<in T, out TResult>,当T或TResult的类型需要根据程序上下文来确定时,也就是说我们的泛型委托类型是动态确定的,那么如何来构造呢?答案就是typeof(Func<,>).MakeGenericType(typeof(T), typeof(TResult))

一、先来看下Type.MakeGenericType的描述。

// C:\Program Files\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\mscorlib.dll
namespace System
{
        //
        // 摘要:
        //     替代由当前泛型类型定义的类型参数组成的类型数组的元素,并返回表示结果构造类型的 System.Type 对象。
        //
        // 参数:
        //   typeArguments:
        //     将代替当前泛型类型的类型参数的类型数组。
        //
        // 返回结果:
        //     System.Type 表示的构造类型通过以下方式形成:用 typeArguments 的元素取代当前泛型类型的类型参数。
        //
        // 异常:
        //   T:System.InvalidOperationException:
        //     当前的类型不表示泛型类型定义。也就是说, System.Type.IsGenericTypeDefinition 返回 false。
        //
        //   T:System.ArgumentNullException:
        //     typeArguments 为 null。- 或 - 任何元素 typeArguments 是 null。
        //
        //   T:System.ArgumentException:
        //     中的元素数 typeArguments 不是当前的泛型类型定义中的类型参数的编号相同。- 或 - 任何元素 typeArguments 不满足当前的泛型类型的相应类型参数指定的约束。-
        //     或 - typeArguments 包含的元素,是指针类型 (System.Type.IsPointer 返回 true),通过 ref 类型 (System.Type.IsByRef
        //     返回 true),或 System.Void。
        //
        //   T:System.NotSupportedException:
        //     在基类中不支持调用的方法。派生类必须提供一个实现。
        public virtual Type MakeGenericType(params Type[] typeArguments);
}

二、示例

通过MakeGenericType方法,从Func<T,TResult>泛型委托类型创建出特定类型Func<string,Object>的委托类型。

    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("\r\n--- 通过基本的泛型委托类型构造特定类型的委托类型。");
            
            //创建一个类型对象,表示基本的泛型委托类型。
            //要省略类型参数(但保留类型参数之间的逗号,使编译器能够推断出参数数量)。
            Type generic = typeof(Func<,>);
            DisplayTypeInfo(generic);
            
            //创建类型数组以替代泛型委托的类型参数,
            //输入参数类型为string,输出参数类型为Object。
            Type[] typeArgs = { typeof(string), typeof(Object) };
            
            //创建特定类型的泛型委托类型对象
            Type constructed = generic.MakeGenericType(typeArgs);
            DisplayTypeInfo(constructed);

            //再通过typeof()直接创建一个类型对象
            Type t = typeof(Func<String, Object>);

            Console.WriteLine("\r\n--- 比较两种方法得到的类型:");
            Console.WriteLine("\t两种类型是否相等? {0}", t == constructed);
            Console.WriteLine("\t两种类型的泛型类型定义是否相等? {0}",t.GetGenericTypeDefinition() == generic);
            Console.Read();
        }
        private static void DisplayTypeInfo(Type t)
        {
            Console.WriteLine("\r\n{0}", t);
            Console.WriteLine("\t是否泛型类型定义? {0}",t.IsGenericTypeDefinition);
            Console.WriteLine("\t是否泛型类型? {0}",t.IsGenericType);

            Type[] typeArguments = t.GetGenericArguments();
            Console.WriteLine("\t枚举类型参数 ({0}):", typeArguments.Length);
            foreach (Type tParam in typeArguments)
            {
                Console.WriteLine("\t\t{0}", tParam);
            }
        }
    }

输出

posted @ 2018-03-26 22:36  览岳  阅读(935)  评论(0编辑  收藏  举报