2008-09-26 12 views
58

¿Cuál es la forma más eficiente de obtener el constructor predeterminado (es decir, el constructor de instancias sin parámetros) de un System.Type?La forma más eficiente de obtener el constructor predeterminado de un Tipo

Estaba pensando algo así como el siguiente código, pero parece que debería haber una forma más sencilla y eficiente de hacerlo.

Type type = typeof(FooBar) 
BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance; 
type.GetConstructors(flags) 
    .Where(constructor => constructor.GetParameters().Length == 0) 
    .First(); 

Respuesta

112
type.GetConstructor(Type.EmptyTypes) 
+6

miembros estáticos que simplemente nunca miras ... esto es increíble. –

+1

Los miembros privados tampoco se miran.Asumiendo que solo necesita público, este parece ser el más simple. Sin embargo, ¿es el más rápido? Estoy trabajando en una prueba ahora mismo para averiguarlo. –

+6

Después de medir este enfoque frente a mi enfoque usando MeasureIt (http://msdn.microsoft.com/en-us/magazine/cc500596.aspx), este enfoque es más rápido en todos los casos, excepto en los más simples, y aun así es apenas más lento. Entonces este es el más simple y el más rápido. ¡Gracias! –

28

Si realmente necesidad el objeto ConstructorInfo, a continuación, vea Curt Hagenlocher's answer.

Por otro lado, si usted está realmente tratando de crear un objeto en tiempo de ejecución de un System.Type, ver System.Activator.CreateInstance - no es sólo a prueba de futuro (Activador maneja más detalles que ConstructorInfo.Invoke), también es mucho menos feo.

+2

Consejo potencialmente peligroso, porque ciertos objetos no tienen constructores por defecto (String es uno). Por lo tanto, si llama esto de cualquier manera, es posible que termine con una excepción de MissingMethod. De hecho, tengo que buscar un constructor predeterminado antes de llamar a este método. – cunningdave

+0

Como escribe cunningdave, lo más probable es que desee capturar y manejar con elegancia al menos una parte del conjunto de excepciones que puede arrojar este método, lo que haría que la llamada sea mucho menos bella de nuevo. La solución con ConstructorInfo por el contrario se ve realmente fea primero, pero le permite manejar todos esos casos excepcionales sin tirar y detectar excepciones primero, lo que puede ser costoso. – buygrush

-2

que le gustaría probar FormatterServices.GetUninitializedObject (Tipo) éste es mejor que Activator.CreateInstance

Sin embargo, este método no llama al constructor de objetos, por lo que si va a configurar los valores iniciales allí, esto no funcionará Compruebe MSDN para esta cosa http://msdn.microsoft.com/en-us/library/system.runtime.serialization.formatterservices.getuninitializedobject.aspx

hay otra manera aquí http://www.ozcandegirmenci.com/post/2008/02/Create-object-instances-Faster-than-Reflection.aspx

sin embargo éste falla si el objec t tiene constructores parametrizar

Esperanza esto ayuda

0

Si sólo se desea obtener el constructor por defecto para crear instancias de la clase, y está recibiendo el tipo como un parámetro de tipo genérico para una función, puede hacer lo siguiente:

T NewItUp<T>() where T : new() 
{ 
    return new T(); 
} 
+3

O simplemente 'nuevo T()' lol –

1

Si tiene el parámetro de tipo genérico, la respuesta de Jeff Bridgman es la mejor. Si solo tiene un objeto Type que represente el tipo que desea construir, podría usar Activator.CreateInstance(Type) como sugirió Alex Lyman, pero me han dicho que es lento (aunque no lo he hecho personalmente).

Sin embargo, si usted se encuentra la construcción de estos objetos con mucha frecuencia, hay un enfoque más elocuente el uso de expresiones LINQ dinámica compilados:

using System; 
using System.Linq.Expressions; 

public static class TypeHelper 
{ 
    public static Func<object> CreateDefaultConstructor(Type type) 
    { 
     NewExpression newExp = Expression.New(type); 

     // Create a new lambda expression with the NewExpression as the body. 
     var lambda = Expression.Lambda<Func<object>>(newExp); 

     // Compile our new lambda expression. 
     return lambda.Compile(); 
    } 
} 

Sólo tiene que llamar al delegado devuelto. Debería almacenar en caché este delegado, porque la recompilación constante de las expresiones de Linq puede ser costosa, pero si guarda en caché el delegado y lo vuelve a usar cada vez, ¡puede ser muy rápido! Yo personalmente uso un diccionario de búsqueda estático indexado por tipo. Esta función es útil cuando se trata de objetos serializados donde solo se puede conocer la información del Tipo.

NOTA: ¡Esto puede fallar si el tipo no es construible o no tiene un constructor predeterminado!

Cuestiones relacionadas