.NET Generics:使用Activator创建的类型作为泛型显示错误的Type?需要解决方法

Cod*_*ike 1 .net c# generics

这真的让我今天难过.我确定它很简单,但是......这是我的示例代码:

using System;
using System.Collections;

namespace ConsoleApplication1
{
    class Program
    {
        public ArrayList SomeProp { get; set; }

        static void Main(string[] args)
        {
            // Get the Type of a property by reflection.
            Type myPropType = typeof(Program).GetProperty("SomeProp").PropertyType;

            // Create an instance of the determined Type.
            var x = Activator.CreateInstance(myPropType);

            // Now try to use that instance, passing to a method that takes a generic.
            WhatAmI(x);

            Console.ReadKey();
        }

        private static void WhatAmI<T>(T x)
        {
            Console.WriteLine("T is: " + typeof(T).FullName);
            Console.WriteLine("x is: " + x.GetType().FullName);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这里的输出是:

T is: System.Object
x is: System.Collections.ArrayList
Run Code Online (Sandbox Code Playgroud)

基本上这里发生的是我在某些课上有一些属性.它来自何处/何处并不重要.重要的是我得到了该属性的PropertyInfo.从那里我用Activator创建了一个新的Type实例.

现在,如果我将创建的实例传递给采用泛型参数的函数,则泛型类型总是作为Object出现,因为Activator.CreateInstance()返回一个Object,因此"var x"是一个Object,在这种情况下,不是一个ArrayList.

我需要发生的是泛型类型是实际类型,在他的情况下是"ArrayList".

我知道有一个我可以使用的Activator.CreateInstance(),但我不能在该方法的尖括号内使用Type(PropertyInfo.PropertyType).

我也可以只是转换返回的对象,如:

myPropType x = (myPropType)Activator.CreateInstance(myPropType);
Run Code Online (Sandbox Code Playgroud)

但很明显,这不会编译...另外它无论如何都不会有效,因为演员是编译时间,我不知道直到运行时的类型,但从概念上讲它是我需要的......

所以我坚持使用这个Type,但我无法弄清楚如何将它传递给WhatAmI()方法,并且让T为ArrayList,而不是Object.

想法?

Mar*_*ell 7

Type在运行时调用泛型方法,您需要使用反射 - MakeGenericMethod尤其是:

typeof(Program).GetMethod("WhatAmI",
    BindingFlags.Static | BindingFlags.NonPublic)
    .MakeGenericMethod(x.GetType()).Invoke(null, new object[] { x });
Run Code Online (Sandbox Code Playgroud)

否则,编译器会<T>从变量类型中推断出- object在这种情况下.

这里的一个侧面是你可以通过只进行一次反射来改进事物- 即不使用Activator,而是使用通用约束:

    private static void WhatAmI<T>() where T : new()
    {
        T x = new T();
        Console.WriteLine("T is: " + typeof(T).FullName);
        Console.WriteLine("x is: " + x.GetType().FullName);
    }
Run Code Online (Sandbox Code Playgroud)

定义没有 arg 的方法,但使用默认构造函数; 然后:

    // Get the Type of a property by reflection.
    Type myPropType = typeof(Program).GetProperty("SomeProp").PropertyType;

    // Now call a generic method just using the type
    typeof(Program).GetMethod("WhatAmI",
        BindingFlags.Static | BindingFlags.NonPublic)
            .MakeGenericMethod(myPropType).Invoke(null, null);
Run Code Online (Sandbox Code Playgroud)

仅使用类型调用方法 - 在方法创建实例.这通常比重复反射更快.