2012-01-13 11 views
16

Vorrei creare un'istanza di una classe utilizzando unità in cui la classe ha due costruttori con lo stesso numero di parametri.Risolvi l'istanza con più costruttori utilizzando l'unità

Ecco l'istanza:

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

E qui sono i costruttori:

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

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

Se provo a fare questo ricevo un'eccezione dicendo Il tipo GradeType ha più costruttori di lunghezza 1 Impossibile disambiguare.

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

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

+0

perché non utilizzare 'Enum.Parse' nella stringa gradeType prima di creare la classe? – jgauffin

+0

sembra proprio un design intuitivo che la classe GradeType converta la stringa. – FatAlbert

+1

Mi sembra una soluzione fragile dal momento che qualsiasi valore inesistente può generare un'eccezione o nascondere un errore. – jgauffin

risposta

26

Sì, è possibile indicare a Unity quale costruttore deve utilizzare, ma è possibile farlo solo quando si registra il 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.

campione costruito con Unity versione 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)); 
+0

proprio quello che stavo cercando! grazie – FatAlbert

+1

Una domanda: quando si annullano le dipendenze, siamo costretti a chiamare la risoluzione esplicitamente sul contenitore? Ma non è male chiamare esplicitamente container.Resolve nel codice dell'applicazione? Ooops, in realtà due domande ;-) – Legends

0

Rimuovere un costruttore e inserire la stringa nell'enumerazione o viceversa, quindi risolvere il problema utilizzando il contenitore.

+0

Non è possibile eseguire il cast di una stringa in un enum. – jgauffin

+0

Enum.Parse - come hai detto – Jason

+0

La stringa da xml è completamente diversa dall'enum (la stringa è in svedese). Tuttavia, quello che sto chiedendo è se è possibile avere più costruttori con lo stesso numero di parametri e usare ancora l'unità per creare le istanze? – FatAlbert

1

Un'opzione alternativa utilizzando la riflessione e seguendo la Strategy Pattern.

1) Creare una classe 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 tua classe GradeType creare i metodi richiesto per la riflessione. ParseArguments analizza gli argomenti per le proprietà e per ognuno che trova, ne copia il valore nella rispettiva proprietà di GradeType utilizzando SetProperty.Dal momento che utilizza il nome della proprietà per l'abbinamento, è importante mantenere lo stesso nome di proprietà attraverso sia il GradeType ei ConstructorArgs concreti:

 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 classe GradeType creare le rispettive proprietà (la mente che si deve utilizzare esattamente gli stessi nomi e tipi che si è utilizzato nella ConstructorArgs concreti, ma è possibile utilizzare qualsiasi modificatori di accesso che ti piace)

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

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

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

6) Ora è possibile registrare il GradeType in Unity utilizzando un unico costruttore, ma è possibile passare in diversi tipi come argomenti quando risolverlo:

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

Se avete intenzione di volte risolvere il tipo in un'iterazione questo approccio potrebbe non essere l'ideale, dal momento che Reflection prevede una penalizzazione delle prestazioni.

Problemi correlati