How to create a new object instance from a Type

后端 未结 12 1736
孤城傲影
孤城傲影 2020-11-22 03:26

One may not always know the Type of an object at compile-time, but may need to create an instance of the Type.

How do you get a new objec

相关标签:
12条回答
  • 2020-11-22 04:09

    The Activator class within the root System namespace is pretty powerful.

    There are a lot of overloads for passing parameters to the constructor and such. Check out the documentation at:

    http://msdn.microsoft.com/en-us/library/system.activator.createinstance.aspx

    or (new path)

    https://docs.microsoft.com/en-us/dotnet/api/system.activator.createinstance

    Here are some simple examples:

    ObjectType instance = (ObjectType)Activator.CreateInstance(objectType);
    
    ObjectType instance = (ObjectType)Activator.CreateInstance("MyAssembly","MyNamespace.ObjectType");
    
    0 讨论(0)
  • 2020-11-22 04:09

    Without use of Reflection:

    private T Create<T>() where T : class, new()
    {
        return new T();
    }
    
    0 讨论(0)
  • 2020-11-22 04:12
    ObjectType instance = (ObjectType)Activator.CreateInstance(objectType);
    

    The Activator class has a generic variant that makes this a bit easier:

    ObjectType instance = Activator.CreateInstance<ObjectType>();
    
    0 讨论(0)
  • 2020-11-22 04:12

    Compiled expression is best way! (for performance to repeatedly create instance in runtime).

    static readonly Func<X> YCreator = Expression.Lambda<Func<X>>(
       Expression.New(typeof(Y).GetConstructor(Type.EmptyTypes))
     ).Compile();
    
    X x = YCreator();
    

    Statistics (2012):

        Iterations: 5000000
        00:00:00.8481762, Activator.CreateInstance(string, string)
        00:00:00.8416930, Activator.CreateInstance(type)
        00:00:06.6236752, ConstructorInfo.Invoke
        00:00:00.1776255, Compiled expression
        00:00:00.0462197, new
    

    Statistics (2015, .net 4.5, x64):

        Iterations: 5000000
        00:00:00.2659981, Activator.CreateInstance(string, string)
        00:00:00.2603770, Activator.CreateInstance(type)
        00:00:00.7478936, ConstructorInfo.Invoke
        00:00:00.0700757, Compiled expression
        00:00:00.0286710, new
    

    Statistics (2015, .net 4.5, x86):

        Iterations: 5000000
        00:00:00.3541501, Activator.CreateInstance(string, string)
        00:00:00.3686861, Activator.CreateInstance(type)
        00:00:00.9492354, ConstructorInfo.Invoke
        00:00:00.0719072, Compiled expression
        00:00:00.0229387, new
    

    Statistics (2017, LINQPad 5.22.02/x64/.NET 4.6):

        Iterations: 5000000
        No args
        00:00:00.3897563, Activator.CreateInstance(string assemblyName, string typeName)
        00:00:00.3500748, Activator.CreateInstance(Type type)
        00:00:01.0100714, ConstructorInfo.Invoke
        00:00:00.1375767, Compiled expression
        00:00:00.1337920, Compiled expression (type)
        00:00:00.0593664, new
        Single arg
        00:00:03.9300630, Activator.CreateInstance(Type type)
        00:00:01.3881770, ConstructorInfo.Invoke
        00:00:00.1425534, Compiled expression
        00:00:00.0717409, new
    

    Statistics (2019, x64/.NET 4.8):

    Iterations: 5000000
    No args
    00:00:00.3287835, Activator.CreateInstance(string assemblyName, string typeName)
    00:00:00.3122015, Activator.CreateInstance(Type type)
    00:00:00.8035712, ConstructorInfo.Invoke
    00:00:00.0692854, Compiled expression
    00:00:00.0662223, Compiled expression (type)
    00:00:00.0337862, new
    Single arg
    00:00:03.8081959, Activator.CreateInstance(Type type)
    00:00:01.2507642, ConstructorInfo.Invoke
    00:00:00.0671756, Compiled expression
    00:00:00.0301489, new
    

    Statistics (2019, x64/.NET Core 3.0):

    Iterations: 5000000
    No args
    00:00:00.3226895, Activator.CreateInstance(string assemblyName, string typeName)
    00:00:00.2786803, Activator.CreateInstance(Type type)
    00:00:00.6183554, ConstructorInfo.Invoke
    00:00:00.0483217, Compiled expression
    00:00:00.0485119, Compiled expression (type)
    00:00:00.0434534, new
    Single arg
    00:00:03.4389401, Activator.CreateInstance(Type type)
    00:00:01.0803609, ConstructorInfo.Invoke
    00:00:00.0554756, Compiled expression
    00:00:00.0462232, new
    

    Full code:

    static X CreateY_New()
    {
        return new Y();
    }
    
    static X CreateY_New_Arg(int z)
    {
        return new Y(z);
    }
    
    static X CreateY_CreateInstance()
    {
        return (X)Activator.CreateInstance(typeof(Y));
    }
    
    static X CreateY_CreateInstance_String()
    {
        return (X)Activator.CreateInstance("Program", "Y").Unwrap();
    }
    
    static X CreateY_CreateInstance_Arg(int z)
    {
        return (X)Activator.CreateInstance(typeof(Y), new object[] { z, });
    }
    
    private static readonly System.Reflection.ConstructorInfo YConstructor =
        typeof(Y).GetConstructor(Type.EmptyTypes);
    private static readonly object[] Empty = new object[] { };
    static X CreateY_Invoke()
    {
        return (X)YConstructor.Invoke(Empty);
    }
    
    private static readonly System.Reflection.ConstructorInfo YConstructor_Arg =
        typeof(Y).GetConstructor(new[] { typeof(int), });
    static X CreateY_Invoke_Arg(int z)
    {
        return (X)YConstructor_Arg.Invoke(new object[] { z, });
    }
    
    private static readonly Func<X> YCreator = Expression.Lambda<Func<X>>(
       Expression.New(typeof(Y).GetConstructor(Type.EmptyTypes))
    ).Compile();
    static X CreateY_CompiledExpression()
    {
        return YCreator();
    }
    
    private static readonly Func<X> YCreator_Type = Expression.Lambda<Func<X>>(
       Expression.New(typeof(Y))
    ).Compile();
    static X CreateY_CompiledExpression_Type()
    {
        return YCreator_Type();
    }
    
    private static readonly ParameterExpression YCreator_Arg_Param = Expression.Parameter(typeof(int), "z");
    private static readonly Func<int, X> YCreator_Arg = Expression.Lambda<Func<int, X>>(
       Expression.New(typeof(Y).GetConstructor(new[] { typeof(int), }), new[] { YCreator_Arg_Param, }),
       YCreator_Arg_Param
    ).Compile();
    static X CreateY_CompiledExpression_Arg(int z)
    {
        return YCreator_Arg(z);
    }
    
    static void Main(string[] args)
    {
        const int iterations = 5000000;
    
        Console.WriteLine("Iterations: {0}", iterations);
    
        Console.WriteLine("No args");
        foreach (var creatorInfo in new[]
        {
            new {Name = "Activator.CreateInstance(string assemblyName, string typeName)", Creator = (Func<X>)CreateY_CreateInstance},
            new {Name = "Activator.CreateInstance(Type type)", Creator = (Func<X>)CreateY_CreateInstance},
            new {Name = "ConstructorInfo.Invoke", Creator = (Func<X>)CreateY_Invoke},
            new {Name = "Compiled expression", Creator = (Func<X>)CreateY_CompiledExpression},
            new {Name = "Compiled expression (type)", Creator = (Func<X>)CreateY_CompiledExpression_Type},
            new {Name = "new", Creator = (Func<X>)CreateY_New},
        })
        {
            var creator = creatorInfo.Creator;
    
            var sum = 0;
            for (var i = 0; i < 1000; i++)
                sum += creator().Z;
    
            var stopwatch = new Stopwatch();
            stopwatch.Start();
            for (var i = 0; i < iterations; ++i)
            {
                var x = creator();
                sum += x.Z;
            }
            stopwatch.Stop();
            Console.WriteLine("{0}, {1}", stopwatch.Elapsed, creatorInfo.Name);
        }
    
        Console.WriteLine("Single arg");
        foreach (var creatorInfo in new[]
        {
            new {Name = "Activator.CreateInstance(Type type)", Creator = (Func<int, X>)CreateY_CreateInstance_Arg},
            new {Name = "ConstructorInfo.Invoke", Creator = (Func<int, X>)CreateY_Invoke_Arg},
            new {Name = "Compiled expression", Creator = (Func<int, X>)CreateY_CompiledExpression_Arg},
            new {Name = "new", Creator = (Func<int, X>)CreateY_New_Arg},
        })
        {
            var creator = creatorInfo.Creator;
    
            var sum = 0;
            for (var i = 0; i < 1000; i++)
                sum += creator(i).Z;
    
            var stopwatch = new Stopwatch();
            stopwatch.Start();
            for (var i = 0; i < iterations; ++i)
            {
                var x = creator(i);
                sum += x.Z;
            }
            stopwatch.Stop();
            Console.WriteLine("{0}, {1}", stopwatch.Elapsed, creatorInfo.Name);
        }
    }
    
    public class X
    {
      public X() { }
      public X(int z) { this.Z = z; }
      public int Z;
    }
    
    public class Y : X
    {
        public Y() {}
        public Y(int z) : base(z) {}
    }
    
    0 讨论(0)
  • 2020-11-22 04:12

    Wouldn't the generic T t = new T(); work?

    0 讨论(0)
  • 2020-11-22 04:12

    Just as an extra to anyone using the above answers that implement:

    ObjectType instance = (ObjectType)Activator.CreateInstance(objectType);
    

    Be careful - if your Constructor isn't "Public" then you will get the following error:

    "System.MissingMethodException: 'No parameterless constructor defined for this object."

    Your class can be Internal/Friend, or whatever you need but the constructor must be public.

    0 讨论(0)
提交回复
热议问题