2011-04-07 7 views
9

Estoy usando Type.GetConstructor(Type.EmptyTypes) para obtener el constructor predeterminado para una clase. Funciona si la clase tiene un constructor predeterminado sin parámetros (class A). Pero no funciona si una clase tiene un constructor con todos los parámetros opcionales (class B). El programa no sabe cuáles son los parámetros opcionales porque solo necesita el constructor predeterminado. ¿Qué declaraciones puedo usar para que funcione en ambos casos? Gracias, agradezco cualquier ayuda!Cómo obtener el constructor predeterminado cuando los parámetros son opcionales

public class A 
{ 
    public A() {} 
} 

public class B 
{ 
    public B(int i = 0, string str = "") {} 
} 
+0

Gracias por todas las respuestas, son muy informativas. Como estas son clases generadas automáticamente, acabo de cambiarla para incluir siempre un constructor sin parámetro. – dlsou

+0

También tenga en cuenta que su clase 'B' no se puede utilizar en genérico para un parámetro de tipo' T' si 'T' tiene la restricción' donde T: new() '. El constructor de instancias públicas no se considera sin parámetros solo porque todos sus parámetros son opcionales. –

Respuesta

5

Decir que tengo la clase siguiente:

public class SomeClass 
{ 
    public SomeClass() 
    { 

    } 

    public SomeClass(int x) 
    { 
    } 

    public SomeClass(int x = 0, int y = 0) 
    { 

    } 
} 

Básicamente, usted está solicitando una consulta que se encuentra el constructores que coinciden con el constructor 1 y 3 anterior? Si es así, utilice esto:

var constuctors = typeof(SomeClass).GetConstructors() 
      .Where(x => x.GetParameters().Count() == 0 
        || x.GetParameters().Count(param => param.GetCustomAttributes(typeof(OptionalAttribute), false).Count() > 0) == x.GetParameters().Count());  

consulta Increíblemente desagradable, pero hace el trabajo de volver a sólo 1 y 3 anteriores.

+1

Vea la respuesta de Damiens, un poco más eficiente. Sin embargo +1 por la idea – nawfal

3

El problema es que los parámetros opcionales no son más que un concepto de tiempo de compilación. Necesitarás especificar el constructor por completo.

var ci = typeof(B).GetConstructor(new [] { typeof(int), typeof(string) }); 

Puede escribir una función de ayuda que invocará el constructor con los valores predeterminados. Mi ejemplo no es tan sólido como debería ser, pero debería comenzar.

static Func<T> CreateDefaultConstructor<T>(ConstructorInfo ci) 
{ 
    var l = new List<object>(); 
    foreach (var p in ci.GetParameters()) 
    { 
     if (p.IsOptional) 
     { 
      l.Add(p.RawDefaultValue); 
     } 
    } 
    return() => (T)ci.Invoke(l.ToArray()); 
} 
2

El problema es que, en el caso de B, que no tiene un constructor sin parámetros.

Los argumentos opcionales son una compilación en tiempo de compilación: en el IL, es un constructor con 2 parámetros (que están marcados con atributos). Como tal, no existe un constructor predeterminado en lo que respecta a Reflexión.

3

El problema es que el compilador de C# produce esto:

public class B 
{ 
    // Methods 
    public B([Optional, DefaultParameterValue(0)] int i, [Optional, DefaultParameterValue("")] string str) 
    { 
    } 
} 

Algo parecido a continuación debería funcionar:

public static class TypeHelper { 
    public static ConstructorInfo GetDefaultConstructor<TType>() { 
     var type = typeof(TType); 
     return type.GetDefaultConstructor(); 
    } 

    public static ConstructorInfo GetDefaultConstructor(this Type type) { 
     if(type == null) throw new ArgumentNullException("type"); 
     var constructor = type.GetConstructor(Type.EmptyTypes); 
     if(constructor == null) { 
      var ctors = 
       from ctor in type.GetConstructors() 
       let prms = ctor.GetParameters() 
       where prms.All(p=>p.IsOptional) 
       orderby prms.Length 
       select ctor;       
      constructor = ctors.FirstOrDefault(); 
     } 
     return constructor; 
    } 
} 
+1

Puede escribir una instrucción LINQ para encontrar todos los parámetros de constructor con los valores opcionales y DefaultParameterValue especificados. – Damian

+0

O simplemente opcional; probablemente nunca se usen solos. –

+0

Buena respuesta, pero el enfoque firstordefault no es apropiado. Estás decidiendo que el operador está sobrecargando para el usuario en lugar de C#.Quiero decir que puede haber casos de ambigüedad del compilador sobre resolución de sobrecarga, pero aquí está decidiendo uno para él :) – nawfal

0

Cuando un constructor, o cualquier otro método, tiene argumentos opcionales no lo hace hacer que el compilador genere múltiples versiones del método. En cambio, genera un único método que tiene todos los parámetros especificados. Los valores predeterminados están codificados en atributos asociados a la firma del método. Estos se usan en el sitio de llamadas para que sus valores sean opcionales.

Así que aquí no hay ningún constructor predeterminado sino uno solo con 2 parámetros

Cuestiones relacionadas