Es posible que no siempre se conozca el Tipo de un objeto en tiempo de compilación, pero puede ser necesario crear una instancia del Tipo. ¿Cómo se obtiene una nueva instancia de objeto de un Tipo?Obtiene una nueva instancia de objeto de un Tipo
Respuesta
El Activator
clase dentro del root System
namespace es bastante poderoso.
Hay muchas sobrecargas para pasar parámetros al constructor y tal. Echa un vistazo a 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
Éstos son algunos ejemplos sencillos:
ObjectType instance = (ObjectType)Activator.CreateInstance(objectType);
ObjectType instance = (ObjectType)Activator.CreateInstance("MyAssembly","MyNamespace.ObjectType");
Una aplicació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í es el mismo enfoque, contenido en un método genérico:
public static T GetNewObject<T>()
{
try
{
return (T)typeof(T).GetConstructor(new Type[] { }).Invoke(new object[] { });
}
catch
{
return default(T);
}
}
¿Programación por excepción? Esto parece una implementación muy pobre cuando simplemente puede reflexionar sobre el tipo para determinar los constructores. – Firoso
Si esto es para algo que se llamará mucho en una instancia de aplicación, es mucho más rápido compilar y almacenar en caché el código dinámico en lugar de usar el activador o ConstructorInfo.Invoke()
. Se compilan dos opciones fáciles para la compilación dinámica Linq Expressions o algunos simples IL
opcodes and DynamicMethod
. De cualquier manera, la diferencia es enorme cuando comienzas a entrar en bucles estrechos o llamadas múltiples.
El enlace "IL opcodes and DynamicMethod" está muerto. –
ObjectType instance = (ObjectType)Activator.CreateInstance(objectType);
La clase Activator
tiene una variante genérica que hace que sea un poco más fácil:
ObjectType instance = Activator.CreateInstance<ObjectType>();
Excepto que esto no funciona para el tiempo de ejecución 'Type t'. –
@Kevin Por supuesto. Tal operación * no puede * funcionar en un lenguaje estáticamente tipado porque no tiene sentido. No puede invocar métodos en un objeto de tipo desconocido.Mientras tanto (= desde que escribimos esta respuesta) C# tiene el constructo 'dynamic' que * does * permite dichos constructos, pero para la mayoría de los propósitos, esta respuesta aún lo cubre. –
@KonradRudolph No es del todo cierto. Primero de C# * does * le permite crear nuevos tipos en tiempo de ejecución. No se puede llamar nada * de forma estáticamente segura *. Así que sí, eres medio correcto. Pero de forma más realista, necesita esto cuando carga ensamblajes en tiempo de ejecución, lo que significa que no se conoce el tipo en tiempo de compilación. C# estaría severamente limitado si no pudieras hacer esto. Quiero decir que simplemente lo has probado tú mismo: ¿de qué otro modo funciona el método Activator que toma una instancia de tipo? Cuando MS escribió la clase Activator no tenían conocimiento en tiempo de compilación de ningún tipo futuro que los usuarios escribirían. – AnorZaken
¿No lo genérico T t = new T();
trabajo?
En realidad, lo haría en una clase/método genérico, pero no para un "Tipo" dado. –
public AbstractType New
{
get
{
return (AbstractType) Activator.CreateInstance(GetType());
}
}
Si desea utilizar el constructor por defecto entonces la solución usando System.Activator
presentado 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 utilizando 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 }
);
Es bastante sencillo. Suponga que su nombre de clase es Car
y el espacio de nombres es Vehicles
, luego pase el parámetro como Vehicles.Car
que devuelve el 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 Fully Qualified Name (es decir, Vehicles.Car
en este caso) es en otro montaje, el Type.GetType
será nulo. En tales casos, tiene un ciclo en todos los ensamblajes y encuentra el Type
. Para eso, puede 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");
En su segundo caso (ensamble externo), podría pasar "Vehículos.Car, OtrosAsamblea" a su primer método y funcionará. Obviamente, OtherAssembly es el nombre del ensamblaje en el que vive. – danmiser
@danmiser Necesita codificación dura del nombre del ensamblado. Para implementar flexibilidad, estoy verificando nulo y el código funciona de manera dinámica :) –
puedo través de esta pregunta porque yo estaba buscando para poner en práctica un método simple para CloneObject clase arbitraria (con un constructor por defecto)
Con método genérico se puede exigir que el tipo implementa Nueva().
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 no genérico asumir el tipo tiene un constructor por defecto y coger 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
¡La expresión compilada es la mejor manera! (para que el rendimiento cree una instancia repetidamente en tiempo de ejecución).
static readonly Func<X> YCreator = Expression.Lambda<Func<X>>(
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, 86):
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<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 para todas las estadísticas! Realmente no necesito este tipo de actuación en este momento, pero sigue siendo muy interesante. :) – AnorZaken
También está TypeDescriptor.CreateInstance (ver http://stackoverflow.com/a/17797389/1242), que puede ser más rápido si se usa con TypeDescriptor.AddProvider –
¿Esto todavía es útil cuando no sabes qué tipo 'X' está en tiempo de ejecución? – ajeh
Sin el uso de Reflexión:
private T Create<T>() where T : class, new()
{
return new T();
}
¿Cómo es útil? Ya debe saber el tipo para llamar a ese método y, si conoce el tipo, puede construirlo sin un método especial. –
Entonces T puede variar en tiempo de ejecución. Útil si trabajas con tipos derivados. –
una nueva T(); fallaría si T no es un tipo de referencia con un constructor sin parámetros. Este método usa contraints para asegurar que T sea un tipo de referencia y que tenga un constructor. –
Ante este problema, el activador funciona cuando hay un ctor sin parámetros. Si esto es una restricción, considere usar
System.Runtime.Serialization.FormatterServices.GetSafeUninitializedObject()
- 1. crear una nueva instancia de un tipo dado como parámetro
- 2. Obtiene instancia de objeto compañero con la nueva API de reflexión de Scala
- 3. Obtiene el tipo real de un parámetro de objeto genérico
- 4. Cómo crear una nueva instancia de clonación del objeto PSObject
- 5. obtener posible instancia/tipo de objeto
- 6. LINQ: la expresión Where devuelve una nueva instancia o referencia a la instancia del objeto
- 7. Obtiene un atributo de objeto
- 8. .net, ¿obtiene un objeto de transacción?
- 9. la creación de una nueva instancia de un tipo en Scala
- 10. ¿Obtiene un tipo de datos XML de un tipo .NET?
- 11. Cómo crear una instancia nueva a partir de un objeto de clase en Python
- 12. WCF aplicación del cliente de servicio que obtiene "Objeto no configurado en una instancia de un objeto"
- 13. .NET: ¿Cómo se obtiene el tipo de objeto nulo?
- 14. Agregar una nueva instancia en weka
- 15. ¿Debo crear una nueva instancia de delegado?
- 16. Crear una instancia de un objeto con un tipo determinado en el tiempo de ejecución
- 17. ¿Hay una forma correcta de devolver una nueva instancia de objeto por referencia en C++?
- 18. Injector.getInstance (..) devuelve una nueva instancia de un producto único
- 19. Obtiene el objeto de clase externo de un objeto de clase interna
- 20. Obtiene nETBIOSName de un objeto UserPrincipal
- 21. Obtiene documento objeto de un elemento secundario
- 22. usando django, ¿cómo construyo una instancia de objeto proxy de una instancia de objeto de superclase?
- 23. ¿Cómo se crea una nueva instancia de una estructura de su tipo en tiempo de ejecución en Go?
- 24. Cómo devolver una nueva instancia de self desde un método de instancia de ruby
- 25. Java: nueva instancia de bytecode
- 26. Obtiene una propiedad de objeto PHP que es un número
- 27. ¿Puedo crear una nueva instancia de mi clase de objeto administrado personalizado sin pasar por NSEntityDescription?
- 28. Obtiene el tipo de GUID
- 29. Obtiene la instancia de la clase <T> [Token de tipo de tiempo de ejecución]
- 30. Obtiene un artículo de un conjunto Java
Me alegro de haber encontrado esto finalmente, pero la segunda llamada no es exactamente correcta, falta una cita y los parms invertidos deben ser: ObjectType instancia = (ObjectType) Activator.CreateInstance ("MyAssembly", "MyNamespace.ObjectType"); – kevinc
Debe llamar a 'Unwrap()' para obtener el tipo real de objeto que desea: ConcreteType instance = (ConcreteType) Activator.CreateInstance (objectType) .Unwrap(); –