简体   繁体   English

类型参数的通用类

[英]Generic class from type parameter

Is there a way to create a generic class from type parameter. 有没有办法从类型参数创建泛型类。

I have something like this: 我有这样的事情:

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>();
    }
}

What I want is to create a GenericClass from a Type. 我想要的是从Type创建GenericClass。 Ex: 例如:

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

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

Here I expect to get instance of GenericClass<OneMoreClass> but I get GenericClass<Type> 在这里,我希望得到GenericClass<OneMoreClass>实例,但我得到了GenericClass<Type>

I also tried using instance of that type. 我也尝试过使用那种类型的实例。 Ex: 例如:

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

This time I get GenericClass<object> 这次我得到了GenericClass<object>

Is there a way to accomplish this task? 有没有办法完成这项任务?

If you know the type you actually want ( OneMoreClass ) at build time, then you should just use it: 如果你在构建时知道你真正想要的类型( OneMoreClass ),那么你应该只使用它:

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. 但我假设你在构建时不知道它,并且必须在运行时获取type 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. 由于在构建时不知道结果类型,因此除了方法中的object (或dynamic )之外,不能返回任何内容。


Here is how much slower (for 100,000 creates) 这是多慢(100,000创建)

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. 所以慢了100多倍。

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. 关于泛型的真实要点是泛型中的<T>构建时由C#编译器解析,并插入真实的类名。 When you have to defer that until run-time, you end up paying the performance price. 当您必须将其推迟到运行时间时,您最终会支付性能价格。

I'm not sure what exactly you are asking here. 我不确定你在这里问的是什么。 If I understood you properly, this is what you are looking for: 如果我理解你,这就是你要找的:

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>();
    }
}

Th usage: 用法:

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

Assertions: 断言:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM