6

有没有办法从类型参数创建一个泛型类。

我有这样的事情:

public class SomeClass
{
    public Type TypeOfAnotherClass { get; set; }
}

public class OneMoreClass
{
}

public class GenericClass<T>
    where T : class
{
    public void DoNothing() {}
}

public class GenericClass
{
    public static GenericClass<T> GetInstance<T>(T ignored)
        where T : class
    {
        return new GenericClass<T>();
    }
}

我想要的是从一个类型创建一个 GenericClass。前任:

var SC = new SomeClass();
SC.TypeOfAnotherClass = typeof(OneMoreClass);
var generic = GenericClass.GetInstance(SC.TypeOfAnotherClass);

Assert.AreEqual(typeof(GenericClass<OneMoreClass>), generic.GetType());

在这里我希望得到实例,GenericClass<OneMoreClass>但我得到GenericClass<Type>

我也尝试使用该类型的实例。前任:

var generic = GenericClass.GetInstance(Activator.CreateInstance(SC.TypeOfAnotherClass));

这次我得到GenericClass<object>

有没有办法完成这个任务?

4

2 回答 2

10

If you know the type you actually want (OneMoreClass) at build time, then you should just use it:

var generic = GenericClass.GetInstance<OneMoreClass>();

But I am assuming you don't know it at build time, and have to get the type at runtime. You can do it with reflection, but it isn't pretty, and is slow:

public class GenericClass
{
    public static object GetInstance(Type type)
    {
        var genericType = typeof(GenericClass<>).MakeGenericType(type);
        return Activator.CreateInstance(genericType);
    }
}

Since you don't know the resulting type at build time, you can't return anything but object (or dynamic) from the method.


Here is how much slower (for 100,000 creates)

public class GenericClass
{
    public static object GetInstance(Type type)
    {
        var genericType = typeof(GenericClass<>).MakeGenericType(type);
        return Activator.CreateInstance(genericType);
    }

    public static GenericClass<T> GetInstance<T>()
        where T : class
    {
        return new GenericClass<T>();
    }
}

    [Test]
    public void CanMakeGenericViaReflection_ButItsSlow()
    {
        var timer = new Stopwatch();
        var SC = new SomeClass();
        SC.TypeOfAnotherClass = typeof(OneMoreClass);

        timer.Start();
        for (int x = 0; x < 100000; x++)
        {
            GenericClass.GetInstance(SC.TypeOfAnotherClass);
        }
        timer.Stop();
        Console.WriteLine("With Reflection: " + timer.ElapsedMilliseconds + "ms.");

        timer.Restart();
        for (int x = 0; x < 100000; x++)
        {
            GenericClass.GetInstance<OneMoreClass>();
        }
        timer.Stop();
        Console.WriteLine("Without Reflection: " + timer.ElapsedMilliseconds + "ms.");
    }

Results:

With Reflection: 243ms.
Without Reflection: 2ms.

So a little over 100x slower.

The real thing to note about generics is that the <T>s in generics are resolved at build-time by the C# compiler, and the real class names are inserted. When you have to defer that until run-time, you end up paying the performance price.

于 2012-04-25T16:13:22.257 回答
2

我不确定你到底在问什么。如果我正确理解你,这就是你要找的:

public class GenericClass
{
    public static GenericClass<T> GetInstance<T>(T ignored)
        where T : class
    {
        return new GenericClass<T>();
    }

    public static GenericClass<T> GetInstance<T>()
        where T : class
    {
        return new GenericClass<T>();
    }
}

用法:

  var generic1 = GenericClass.GetInstance<OneMoreClass>();
  var generic2 = GenericClass.GetInstance(new OneMoreClass());

断言:

Assert.AreEqual(typeof(GenericClass<OneMoreClass>), generic1.GetType());
Assert.AreEqual(typeof(GenericClass<OneMoreClass>), generic2.GetType());
于 2012-04-25T16:07:25.317 回答