c# unity-container ioc-container

c# - Resuelve la instancia con mĂșltiples constructores usando la unidad.



unity-container ioc-container (3)

Elimine un constructor y convierta la cadena a la enumeración, o viceversa, y luego resuélvala utilizando el contenedor.

Me gustaría crear una instancia de una clase usando la unidad donde la clase tiene dos constructores con el mismo número de parámetros.

Aquí está la instanciación:

_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, obtengo una excepción que dice que el tipo GradeType tiene varios constructores de longitud 1. No se puede desambiguar .

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

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


Sí, es posible decirle a Unity qué constructor debería usar, pero solo puedes hacerlo cuando registres tu 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 Unity versión 2.1.505:

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


Una opción alternativa utilizando Reflexión y siguiendo el Patrón de Estrategia .

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

public abstract class ConstructorArgs { }

2) Crea 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) Ahora en su clase de GradeType cree los métodos requeridos para la Reflexión. ParseArguments escanea los argumentos en busca de propiedades y, para cada una que encuentra, copia su valor a la propiedad respectiva del tipo de grado utilizando el SetProperty. Ya que usa el nombre de la propiedad para la coincidencia, es importante mantener el mismo nombre de propiedad tanto en el GradeType como en el ConstructorArgs concreto:

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 su clase de GradeType cree las propiedades respectivas (recuerde que debe usar exactamente los mismos nombres y tipos que usó en el ConstructorArgs concreto, pero puede usar cualquier modificador de acceso que desee)

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

5) Cree un constructor para su clase de GradeType con un parámetro de tipo ConstructorArgs:

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

6) Ahora puede registrar el GradeType en Unity utilizando un único constructor, pero puede pasar diferentes tipos como argumentos al resolverlo:

_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 planea resolver repetidamente su tipo en una iteración, este enfoque podría no ser ideal, ya que Reflection viene con una penalización de rendimiento.