Obtener una nueva instancia de objeto de un Tipo

Es posible que uno no siempre sepa el Tipo de un objeto en tiempo de comstackción, pero puede necesitar crear una instancia del Tipo. ¿Cómo se obtiene una nueva instancia de objeto de un Tipo?

La clase Activator dentro del espacio de nombres del System raíz es bastante poderosa.

Hay muchas sobrecargas para pasar parámetros al constructor y tal. Consulte la documentación en:

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

o (nueva ruta)

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

Aquí hay algunos ejemplos simples:

 ObjectType instance = (ObjectType)Activator.CreateInstance(objectType); ObjectType instance = (ObjectType)Activator.CreateInstance("MyAssembly","MyNamespace.ObjectType"); 
 ObjectType instance = (ObjectType)Activator.CreateInstance(objectType); 

La clase Activator tiene una variante genérica que hace esto un poco más fácil:

 ObjectType instance = Activator.CreateInstance(); 

La expresión comstackda es la mejor manera! (para que el rendimiento cree una instancia repetidamente en tiempo de ejecución).

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

Estadísticas (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 

Estadísticas (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 

Estadísticas (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 

Estadísticas (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 

Código completo:

 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 YCreator = Expression.Lambda>( Expression.New(typeof(Y).GetConstructor(Type.EmptyTypes)) ).Compile(); static X CreateY_CompiledExpression() { return YCreator(); } private static readonly Func YCreator_Type = Expression.Lambda>( 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 YCreator_Arg = Expression.Lambda>( 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)CreateY_CreateInstance}, new {Name = "Activator.CreateInstance(Type type)", Creator = (Func)CreateY_CreateInstance}, new {Name = "ConstructorInfo.Invoke", Creator = (Func)CreateY_Invoke}, new {Name = "Compiled expression", Creator = (Func)CreateY_CompiledExpression}, new {Name = "Compiled expression (type)", Creator = (Func)CreateY_CompiledExpression_Type}, new {Name = "new", Creator = (Func)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 += xZ; } 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)CreateY_CreateInstance_Arg}, new {Name = "ConstructorInfo.Invoke", Creator = (Func)CreateY_Invoke_Arg}, new {Name = "Compiled expression", Creator = (Func)CreateY_CompiledExpression_Arg}, new {Name = "new", Creator = (Func)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 += xZ; } 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) {} } 

Una implementación de este problema es intentar llamar al constructor sin parámetros del Tipo:

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

Aquí está el mismo enfoque, contenido en un método genérico:

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

Es bastante simple. Suponga que su nombre de clase es Car y el espacio de nombre es Vehicles , luego pase el parámetro como Vehicles.Car que devuelve objeto de tipo Car . De esta manera, puedes crear cualquier instancia de cualquier clase dinámicamente.

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

Si su Nombre Completamente Calificado (es decir, Vehicles.Car en este caso) está en otro ensamblado, Type.GetType será nulo. En tales casos, tiene un bucle en todos los ensamblajes y encuentra el Type . Para eso puedes usar el siguiente código

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

Y puede obtener la instancia llamando al método anterior.

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

Si esto es para algo que se llamará mucho en una instancia de aplicación, es mucho más rápido comstackr y almacenar en caché el código dynamic en lugar de usar el activador o ConstructorInfo.Invoke() . Dos opciones fáciles para la comstackción dinámica son Linq Expressions comstackdas o algunos DynamicMethod IL simples y DynamicMethod . De cualquier manera, la diferencia es enorme cuando comienzas a entrar en bucles estrechos o llamadas múltiples.

Sin uso de Reflection:

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

Si desea utilizar el constructor predeterminado, entonces la solución que usa System.Activator presentada anteriormente es probablemente la más conveniente. Sin embargo, si el tipo carece de un constructor predeterminado o si tiene que usar uno no predeterminado, entonces una opción es usar reflection o System.ComponentModel.TypeDescriptor . En caso de reflexión, basta con conocer el nombre del tipo (con su espacio de nombre).

Ejemplo usando la reflexión:

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

Ejemplo usando 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 } ); 

¿No sería el genérico T t = new T(); ¿trabajo?

Dado este problema, el activador funcionará cuando haya un ctor sin parámetros. Si esto es una restricción, considere usar

 System.Runtime.Serialization.FormatterServices.GetSafeUninitializedObject() 

Puedo cruzar esta pregunta porque estaba buscando implementar un método CloneObject simple para la clase arbitraria (con un constructor predeterminado)

Con el método genérico puede requerir que el tipo implemente Nuevo ().

 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 

Con la suposición no genérica, el tipo tiene un constructor predeterminado y captura una excepción si no lo hace.

 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 
 public AbstractType New { get { return (AbstractType) Activator.CreateInstance(GetType()); } }