Risolvi l’istanza con più costruttori usando l’unità

Mi piacerebbe creare un’istanza di una class usando unity dove la class ha due costruttori con lo stesso numero di parametri.

Ecco l’istanziazione:

_unityContainer.Resolve(new ParameterOverride("gradeTypeStringFromXmlFile", gradeTypeStringFromXmlFile)); 

E qui ci sono i costruttori:

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

Se provo a farlo, ottengo un’eccezione dicendo che il tipo GradeType ha più costruttori di lunghezza 1. Imansible disambiguare .

Posso impostare l’attributo [InjectionConstructor] su un costruttore per farlo funzionare con uno, ma poi non riesco a creare un’istanza con l’unità usando l’altro costruttore.

È un modo per avere più costruttori con lo stesso numero di parametri e usare ancora l’unità per creare le istanze?

Sì, è ansible dire a Unity quale costruttore dovrebbe usare, ma puoi farlo solo quando registri il tuo tipo con InjectionConstructor . Se vuoi usare entrambi i costruttori è anche complicato perché devi dare un nome alle tue registrazioni e usare quel nome quando si risolve.

Esempio realizzato con Unity versione 2.1.505:

 var continer = new UnityContainer(); continer.RegisterType("stringConstructor", new InjectionConstructor(typeof(string))); continer.RegisterType("enumConstructor", new InjectionConstructor(typeof(EnumGradeType))); IGradeType stringGradeType = continer.Resolve("stringContructor" , new DependencyOverride(typeof(string), "some string")); IGradeType enumGradeType = continer.Resolve("enumConstructor", new DependencyOverride(typeof(EnumGradeType), EnumGradeType.Value)); 

Un’opzione alternativa che utilizza Reflection e che segue il modello di strategia .

1) Creare una class base per gli argomenti dei costruttori

 public abstract class ConstructorArgs { } 

2) Creare una sequenza di diverse classi di argomenti concreti:

 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) Ora nella class GradeType creare i metodi richiesti per Reflection. ParseArguments analizza gli argomenti per le proprietà e per ognuno che trova, ne copia il valore nella rispettiva proprietà di GradeType utilizzando SetProperty. Poiché utilizza il nome della proprietà per la corrispondenza, è importante mantenere lo stesso nome di proprietà su GradeType e Concrete ConstructorArgs:

  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) Nella class GradeType crea le rispettive proprietà (ricorda che devi usare esattamente gli stessi nomi e tipi che hai usato nel ConstructorArgs concreto ma puoi usare qualsiasi modificatore di accesso che ti piace)

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

5) Creare un costruttore per la class GradeType con un parametro di tipo ConstructorArgs:

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

6) Ora puoi registrare GradeType in Unity usando un singolo costruttore ma puoi passare in diversi tipi come argomenti per risolverlo:

  _unityContainer.RegisterType( new InjectionConstructor( typeof(ConstructorArgs) )); var args1 = new StringArg(gradeTypeStringFromXmlFile); // string IGradeType gradeType1 = _unityContainer.Resolve( new ResolverOverride[]{new ParameterOverride("args", args1)}); var args2 = new EnumArg(gradeType); // enum IGradeType gradeType2 = _unityContainer.Resolve( new ResolverOverride[]{new ParameterOverride("args", args2)}); 

Se hai intenzione di risolvere ripetutamente il tuo tipo in una iterazione, questo approccio potrebbe non essere l’ideale, poiché Reflection prevede una penalizzazione delle prestazioni.

Rimuovere un costruttore e lanciare la stringa sull’enumerazione o viceversa, quindi risolvere il problema utilizzando il contenitore.