2012-01-13 20 views
16

Me gustaría crear una instancia de una clase usando unity donde la clase tenga dos constructores con la misma cantidad de parámetros.Resolver instancia con múltiples constructores usando unity

Aquí es la creación de instancias:

_unityContainer.Resolve<IGradeType>(new ParameterOverride("gradeTypeStringFromXmlFile", gradeTypeStringFromXmlFile)); 

Y aquí están los constructores:

public GradeType(string gradeTypeStringFromXmlFile) 
    { 
     _gradeTypeStringFromXmlFile = gradeTypeStringFromXmlFile; 
    } 

    public GradeType(Enum.GradeType gradeType) 
    { 
     _gradeType = gradeType; 
    } 

Si trato de hacer esto llego diciendo una excepción El tipo GradeType tiene varios constructores de longitud 1 . No se pudo eliminar la ambigüedad.

Puedo establecer el atributo [InjectionConstructor] sobre un constructor para que funcione con uno, pero luego no puedo crear una instancia con unity utilizando el otro constructor.

¿Es de alguna manera tener varios constructores con igual cantidad de parámetros y aún usar la unidad para crear las instancias?

+0

¿por qué no utilizar 'Enum.Parse' en la cadena gradeType antes de crear la clase? – jgauffin

+0

, se siente como un diseño intuitivo que la clase GradeType convierte la cadena. – FatAlbert

+1

Parece ser una solución frágil para mí, ya que cualquier valor no existente arrojará una excepción u ocultará un error. – jgauffin

Respuesta

26

Sí, es posible decirle a Unity qué constructor debería usar, pero solo puede hacerlo cuando registra su tipo con InjectionConstructor. Si desea usar ambos constructores, es incluso complicado porque tiene que nombrar sus registros y usar ese nombre al resolver.

Muestra construida con la versión 2.1.505 Unidad:

var continer = new UnityContainer(); 

continer.RegisterType<IGradeType, GradeType>("stringConstructor", 
    new InjectionConstructor(typeof(string))); 

continer.RegisterType<IGradeType, GradeType>("enumConstructor", 
    new InjectionConstructor(typeof(EnumGradeType))); 

IGradeType stringGradeType = continer.Resolve<IGradeType>("stringContructor" , 
    new DependencyOverride(typeof(string), "some string")); 

IGradeType enumGradeType = continer.Resolve<IGradeType>("enumConstructor", 
    new DependencyOverride(typeof(EnumGradeType), EnumGradeType.Value)); 
+0

¡justo lo que estaba buscando! gracias – FatAlbert

+1

Una pregunta: cuando se anulan las dependencias que estamos obligados a llamar, ¿se resuelven explícitamente en el contenedor? Pero, ¿no es malo llamar explícitamente a container.Resolve en su código de aplicación? Ooops, en realidad dos preguntas ;-) – Legends

0

Elimine un constructor y coloque la cadena en la enumeración, o viceversa, y luego resuelva utilizando el contenedor.

+0

No puedes convertir una cadena en una enumeración. – jgauffin

+0

Enum.Parse - como dijiste – Jason

+0

La cadena del xml es completamente diferente de la enumeración (la cadena está en sueco). Sin embargo, lo que estoy preguntando es si es posible tener múltiples constructores con la misma cantidad de parámetros y aún usar la unidad para crear las instancias. – FatAlbert

1

Una opción alternativa utilizando la reflexión y siguiendo el Strategy Pattern.

1) Crear una clase base para los argumentos de los constructores

public abstract class ConstructorArgs 
{ 
} 

2) Crear una secuencia de diferentes clases de argumentos concretos:

public class StringArg : ConstructorArgs 
{ 
    public string _gradeTypeStringFromXmlFile { get; set; } 

    public StringArg (string gradeTypeStringFromXmlFile) 
    { 
     this._gradeTypeStringFromXmlFile = gradeTypeStringFromXmlFile ; 
    } 
} 

public class EnumArg : ConstructorArgs 
{ 
    public Enum.GradeType _gradeType { get; set; } 

    public EnumArg (Enum.GradeType gradeType) 
    { 
     this._gradeType = gradeType ; 
    } 
} 

3) En su clase GradeType crear los métodos requerido para la Reflexión. ParseArguments escanea los argumentos para las propiedades y para cada uno que encuentra, copia su valor a la propiedad respectiva de GradeType usando SetProperty.Dado que se usa el nombre de la propiedad para el juego, es importante mantener el mismo nombre de propiedad a través tanto de la GradeType y los ConstructorArgs concretas:

 private void SetProperty(String propertyName, object value) 
     { 
      var property = this.GetType().GetProperty(propertyName); 
      if (property != null) 
       property.SetValue(this, value); 
     } 
     private void ParseArguments(ConstructorArgs args) 
     { 
      var properties = args.GetType().GetProperties(); 
      foreach (PropertyInfo propertyInfo in properties) 
      { 
       this.SetProperty(propertyInfo.Name, 
        args.GetType().GetProperty(propertyInfo.Name).GetValue(args)); 
      } 
     } 

4) En la clase GradeType crear las respectivas propiedades (cuenta que debe utilizar exactamente los mismos nombres y tipos que utilizó en los ConstructorArgs concretas pero se puede usar cualquier modificador de acceso se quiere)

public string _gradeTypeStringFromXmlFile { get; set; } 
    public Enum.GradeType _gradeType { get; set; } 

5) Crear un constructor para la clase GradeType con un parámetro de ConstructorArgs tipo:

public GradeType(ConstructorArgs args) 
    { 
     this.ParseArguments(args); 
    } 

6) Ahora puede registrar el GradeType en la Unidad utilizando un único constructor pero se pueden pasar en diferentes tipos como argumentos al resolver que:

_unityContainer.RegisterType<IGradeType, GradeType>(
     new InjectionConstructor(typeof(ConstructorArgs))); 

    var args1 = new StringArg(gradeTypeStringFromXmlFile); // string 
    IGradeType gradeType1 = _unityContainer.Resolve<IGradeType>(
     new ResolverOverride[]{new ParameterOverride("args", args1)}); 

    var args2 = new EnumArg(gradeType); // enum 
    IGradeType gradeType2 = _unityContainer.Resolve<IGradeType>(
     new ResolverOverride[]{new ParameterOverride("args", args2)}); 

Si usted está planeando para resolver en repetidas ocasiones su tipo en una iteración ese enfoque podría no ser ideal, ya que Reflection viene con una penalización de rendimiento.

Cuestiones relacionadas