【问题标题】:Generic class from type parameter来自类型参数的泛型类
【发布时间】:2012-04-25 13:45:49
【问题描述】:

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

我有这样的事情:

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&lt;OneMoreClass&gt; 的实例,但我得到GenericClass&lt;Type&gt;

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

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

这次我收到GenericClass&lt;object&gt;

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

【问题讨论】:

    标签: c# generics types


    【解决方案1】:

    如果您在构建时知道您真正想要的类型 (OneMoreClass),那么您应该使用它:

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

    但我假设您在构建时不知道它,并且必须在运行时获取type。 你可以通过反射来做到这一点,但它并不漂亮,而且很慢:

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

    由于您在构建时不知道生成的类型,因此您无法从该方法返回除object(或dynamic)之外的任何内容。


    这是慢多少(对于 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.");
        }
    

    结果:

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

    所以慢了 100 倍多一点。

    关于泛型真正需要注意的是泛型中的&lt;T&gt;s 是由C# 编译器在构建时 解析的,并且插入了真正的类名。当您不得不将其推迟到运行时,您最终会付出性能代价。

    【讨论】:

    • @Gabe - 我在答案中添加了更多内容,以显示使用反射对性能的影响。
    • 所以“慢”的意思是“需要 2 微秒”。如果您每秒只执行几千次,这相当快,但如果您需要执行数百万次,那就太慢了。
    • 非常感谢!这正是我想要的。关于返回的object:我将interfaceGenericClass 作为转换对象。并且性能不会影响我,因为一次只创建一种类型的一个实例。非常感谢,我花了 2 周时间寻找这个解决方案。
    【解决方案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());
    

    【讨论】:

      猜你喜欢
      • 2011-06-13
      • 1970-01-01
      • 2020-05-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-09
      相关资源
      最近更新 更多