604

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 object instance from a Type?

12 답변


759

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");


  • Glad to have finally found this, but second call is not exactly right, missing a quote and parms reversed, should be: ObjectType instance = (ObjectType)Activator.CreateInstance("MyAssembly","MyNamespace.ObjectType"); - kevinc
  • You need to call 'Unwrap()' to get the actual type of object you want: ConcreteType instance = (ConcreteType)Activator.CreateInstance(objectType).Unwrap(); - Ε Г И І И О
  • How does ObjectType instance match the OP's condition "One may not always know the type of an object at compile-time" ? :P - MA-Maddin
  • @MA-Maddin okay then, object instance = Activator.CreateInstance(...);. - BrainSlugs83

119

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

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

ObjectType instance = Activator.CreateInstance<ObjectType>();


  • Except this doesn't work for runtime Type t. - Kevin P. Rice
  • @Kevin Of course. Such an operation can’t work in a statically typed language because it doesn’t make sense. You cannot invoke methods on an object of unknown type. In the meantime (= since writing this answer) C# has got the dynamic construct which does allow such constructs but for most purposes this answer still covers it. - Konrad Rudolph
  • @KonradRudolph Not quite true. First of c# does allow you to create new types at runtime. You just can't call anything on them in a statically safe way. So yeah, you are half correct. But more realistically you need this when you load assemblies at runtime, which means the type isn't known at compile time. C# would be severely limited if you couldn't do this. I mean you just proved it yourself: how else does the Activator method that takes a type-instance work? When MS wrote the Activator class they had no compile-time knowledge of any future types users would write. - AnorZaken
  • @AnorZaken My comment says nothing about creating types at runtime. Of course you can do that, but you can’t use them statically in the same context (you can host a full statically compiled program of course). That’s all my comment is saying. - Konrad Rudolph
  • @KonradRudolph Ah sorry, misinterpreted "such an operation" to mean instantiating a type that's only known at runtime; instead of meaning using a runtime type as a generic type parameter. - AnorZaken

93

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

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) {}
}


  • +1 for all the statistics! I don't really need this kind of performance at the moment, but still very interesting. :) - AnorZaken
  • Also there is TypeDescriptor.CreateInstance (see stackoverflow.com/a/17797389/1242) which can be quicker if used with TypeDescriptor.AddProvider - Lars Truijens
  • Is this still useful when you do not know what type X is at runtime? - ajeh
  • @ajeh Yes. Change typeof(T) to Type.GetType(..). - Serj-Tm
  • @Serj-Tm No, that won't work if type X is a runtime Type. - NetMage

39

One implementation of this problem is to attempt to call the parameter-less constructor of the Type:

public static object GetNewObject(Type t)
{
    try
    {
        return t.GetConstructor(new Type[] { }).Invoke(new object[] { });
    }
    catch
    {
        return null;
    }
}

Here is the same approach, contained in a generic method:

public static T GetNewObject<T>()
{
    try
    {
        return (T)typeof(T).GetConstructor(new Type[] { }).Invoke(new object[] { });
    }
    catch
    {
        return default(T);
    }
}


  • Exception driven programming? This seems like a very poor implementation when you can simply reflect over the type to determine constructors. - Firoso

12

Its pretty simple. Assume that your classname is Car and the namespace is Vehicles, then pass the parameter as Vehicles.Car which returns object of type Car. Like this you can create any instance of any class dynamically.

public object GetInstance(string strNamesapace)
{         
     Type t = Type.GetType(strNamesapace); 
     return  Activator.CreateInstance(t);         
}

If your Fully Qualified Name(ie, Vehicles.Car in this case) is in another assembly, the Type.GetType will be null. In such cases, you have loop through all assemblies and find the Type. For that you can use the below code

public object GetInstance(string strFullyQualifiedName)
{
     Type type = Type.GetType(strFullyQualifiedName);
     if (type != null)
         return Activator.CreateInstance(type);
     foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
     {
         type = asm.GetType(strFullyQualifiedName);
         if (type != null)
             return Activator.CreateInstance(type);
     }
     return null;
 }

And you can get the instance by calling the above method.

object objClassInstance = GetInstance("Vehicles.Car");


  • In your second case (external assembly), you could just pass in "Vehicles.Car,OtherAssembly" to your first method and it will work. Obviously OtherAssembly is the name of the assembly it lives in. - danmiser
  • @danmiser That needs hard coding the assembly name. In order to implement flexibility I am checking null and the code works in dynamic way :) - Sarath Avanavu

12

If this is for something that will be called a lot in an application instance, it's a lot faster to compile and cache dynamic code instead of using the activator or ConstructorInfo.Invoke(). Two easy options for dynamic compilation are compiled Linq Expressions or some simple IL opcodes and DynamicMethod. Either way, the difference is huge when you start getting into tight loops or multiple calls.


  • "IL opcodes and DynamicMethod" link is dead. - Judge Bread

9

Without use of Reflection:

private T Create<T>() where T : class, new()
{
    return new T();
}


  • How is this useful? You have to know the type already to call that method, and if you know the type you can construct it without a special method. - Kyle Delaney
  • So T can vary at runtime. Useful if you work with deríved Types. - user887983
  • a new T(); would fail if T isn't a reference type with parameterless constructor, This methods uses contraints to ensure T is reference type and has a constructor. - user887983
  • How can T vary at runtime? Don't you have to know T at design time in order to call Create <>? - Kyle Delaney
  • If you work with generic classes and interfaces in factories, the types that implements the interface should be instanciated may vary. - user887983

7

If you want to use the default constructor then the solution using System.Activator presented earlier is probably the most convenient. However, if the type lacks a default constructor or you have to use a non-default one, then an option is to use reflection or System.ComponentModel.TypeDescriptor. In case of reflection, it is enough to know just the type name (with its namespace).

Example using reflection:

ObjectType instance = 
    (ObjectType)System.Reflection.Assembly.GetExecutingAssembly().CreateInstance(
        typeName: objectType.FulName, // string including namespace of the type
        ignoreCase: false,
        bindingAttr: BindingFlags.Default,
        binder: null,  // use default binder
        args: new object[] { args, to, constructor },
        culture: null, // use CultureInfo from current thread
        activationAttributes: null
    );

Example using TypeDescriptor:

ObjectType instance = 
    (ObjectType)System.ComponentModel.TypeDescriptor.CreateInstance(
        provider: null, // use standard type description provider, which uses reflection
        objectType: objectType,
        argTypes: new Type[] { types, of, args },
        args: new object[] { args, to, constructor }
    );


7

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


  • Actually, it would in a generic class/method, but not for a given "Type". - Brady Moritz
  • Assumes that the type T has the 'new()' constraint. - Rob Von Nesselrode

5

Given this problem the Activator will work when there is a parameterless ctor. If this is a constraint consider using

System.Runtime.Serialization.FormatterServices.GetSafeUninitializedObject()


3

public AbstractType New
{
    get
    {
        return (AbstractType) Activator.CreateInstance(GetType());
    }
}


3

I can across this question because I was looking to implement a simple CloneObject method for arbitrary class (with a default constructor)

With generic method you can require that the type implements New().

Public Function CloneObject(Of T As New)(ByVal src As T) As T
    Dim result As T = Nothing
    Dim cloneable = TryCast(src, ICloneable)
    If cloneable IsNot Nothing Then
        result = cloneable.Clone()
    Else
        result = New T
        CopySimpleProperties(src, result, Nothing, "clone")
    End If
    Return result
End Function

With non-generic assume the type has a default constructor and catch an exception if it doesn't.

Public Function CloneObject(ByVal src As Object) As Object
    Dim result As Object = Nothing
    Dim cloneable As ICloneable
    Try
        cloneable = TryCast(src, ICloneable)
        If cloneable IsNot Nothing Then
            result = cloneable.Clone()
        Else
            result = Activator.CreateInstance(src.GetType())
            CopySimpleProperties(src, result, Nothing, "clone")
        End If
    Catch ex As Exception
        Trace.WriteLine("!!! CloneObject(): " & ex.Message)
    End Try
    Return result
End Function

Linked


Latest