Generic class from type parameter

前端 未结 2 511
情书的邮戳
情书的邮戳 2021-01-12 22:32

Is there a way to create a generic class from type parameter.

I have something like this:

public class SomeClass
{
    public Type TypeOfAnotherClass         


        
相关标签:
2条回答
  • 2021-01-12 23:23

    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.

    0 讨论(0)
  • 2021-01-12 23:26

    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());
    
    0 讨论(0)
提交回复
热议问题