7

ho una classe di base di base avendo dependecy Dep e di default e iniezione Constructor-Implicitamente l'iniezione di dipendenza in classe Base mentre la classe derivata viene risolto attraverso l'Unità

Class Base : IBase 
{ 

    public IDep Dep { get; set; } 

    public Base() 
    { 
     Console.WriteLine("Default Constructor Base "); 
    } 

    [InjectionConstructor] 
    public Base(IDep dep) 
    { 
     Console.WriteLine("Injection Constructor Base "); 
     Dep = dep;    
    } 
} 

ho pensato che Dipendenza dep dovrebbe ottenere iniettato automaticamente (attraverso Constructor Iniezione) quando la classe derivata viene risolta.

Ma questo non sembra funzionare quando derivo una classe da esso e Risolvi quella classe, Invece viene chiamato un Costruttore di Base predefinito.

Posso solo farlo funzionare quando richiamo esplicitamente il costruttore dalla classe derivata.

class Derived : Base 
{ 

    public Derived() 
    { 
     Console.WriteLine("Default Constructor Derived "); 
    } 

    public Derived (IDep dep) : base(dep1) 
    { 
     Console.WriteLine("Injection Constructor Derived ");    
    } 
} 

Ha unità fornisce alcun modo diretto per chiamare implicitamente il costruttore iniezione di classe di base (non per chiamata construtor esplicito)? Se no, c'è qualche ragione per cui il contenitore di unità non sta facendo da solo ??

+0

I tuoi problemi sono causati da avere più costruttori. I tuoi servizi dovrebbero avere un solo costruttore. Avere [più costruttori è un anti-pattern] (https://www.cuttingedge.it/blogs/steven/pivot/entry.php?id=97) e dovrebbe essere evitato. – Steven

+0

@Steven Ho capito che più costruttori è un anti-pattern. Ma la rimozione del costruttore predefinito non risolve lo scopo qui. –

+0

Penso che in realtà risolva i tuoi problemi, perché se sia "Base" che "Derivato" contengono ogni singolo costruttore che accetta le dipendenze richieste, il problema non esisterà affatto. Sono d'accordo tuttavia con @BatteryBackupUnit che avere una classe base potrebbe non essere il miglior design. – Steven

risposta

11

No, l'unità non è in grado di farlo. In realtà, non c'è un solo contenitore che possa farlo. Un costruttore è lì per creare un'istanza di una classe. Se chiami due costruttori, finirai con due istanze. Se la classe base è astratta, non puoi nemmeno chiamare il suo costruttore (eccetto i costruttori derivati ​​come sai).

Quindi, in base alle limitazioni di C# .net, se si desidera utilizzare l'iniezione del costruttore, funzionerà solo se si inserisce esplicitamente il valore nel costruttore Derived che chiama il costruttore non predefinito Base.

Tuttavia, è possibile scegliere di utilizzare invece l'iniezione di proprietà o metodo. Con questi non è necessario aggiungere la dipendenza a ogni costruttore di una classe derivata.

Property Injection:

class Base 
{ 
    [Dependency] 
    public IDep Dep { get; set; } 
} 

Method Injection:

class Base 
{ 
    private IDep dep; 

    [InjectionMethod] 
    public void Initialize(IDep dep) 
    { 
     this.dep = dep; 
    } 
} 

Si prega di notare:

  • L'oggetto viene creata un'istanza (ctor iniezione) prima del metodo/iniezione di proprietà viene eseguita
  • Potrebbe essere sufficiente per adattare il design per non richiedere una classe base, vedere Composition over Inheritance
3

Questo è come si dovrebbe risolvere il problema:

class abstract Base : IBase 
{ 
    private readonly IDep dep; 

    protected Base(IDep dep) 
    { 
     if (dep == null) throw new ArgumentNullException("dep"); 
     this.dep = dep; 
    } 
} 

Ora la vostra classe di base ha un solo costruttore e questo costruttore definisce tutte le dipendenze richieste dalla classe. C'è solo un modo per creare questa classe e la classe proteggerà i suoi invarianti. La dipendenza è posizionata in un campo privato poiché le altre classi non hanno alcun senso nell'accedere a questa dipendenza.

Con questa classe di base, la classe derivata sarà simile a questa:

class Derived : Base 
{ 
    private readonly IDep dep; 

    public Derived(IDep dep) : base(dep) 
    { 
     this.dep = dep; 
    } 
} 

Qui la classe derivata ha anche un unico costruttore che definisce le dipendenze questa classe richiede. Non può essere creato in un modo diverso. Nel caso in cui la classe utilizzi la dipendenza stessa, dovrebbe archiviare la dipendenza in un campo privato per un uso successivo. Si noti inoltre che poiché questa classe ha un solo costruttore, non vi è alcuna ambiguità in quale costruttore chiamare e non vi è alcun motivo per contrassegnare il costruttore con un attributo [InjectionConstructor].

Si noti che sono d'accordo con BatteryBackupUnit. Poiché applico Dependency Injection e i principi SOLID alle mie applicazioni, vedo poco motivo per utilizzare più le classi base. L'uso della composizione invece dell'eredità spesso riduce la complessità del sistema.

+0

Sì, posso fare così. Ma il mio obiettivo non era quello di usare la chiamata Costruttore esplicita (: base (dep)). E sì per Costruttore multiplo, sono d'accordo con te che dovrei evitare Costruttore multiplo. Sono d'accordo con BatteryBackupUnit che l'unità non può chiamare implicitamente il Costruttore di Injection in quanto è limitazioni di C# .net –

+0

Vorrei dichiarare 'dep' come' protected readonly' nella classe base. Il modificatore 'protected' consente alle classi derivate di accedere a' dep', mentre 'readonly' ne impedisce le modifiche. Ciò rende superflua la duplicazione della variabile 'dep' e la sua inizializzazione nella classe derivata. –

0

La soluzione semplice e diretta consiste nell'avere un "InjectionMethod" nella classe Base.

> public abstract class Base : IBase 
>  { 
> 
>   private IDep dep; 
> 
>   [InjectionMethod] 
>   public void Initialize(IDep dep) 
>   { 
>    if (dep == null) throw new ArgumentNullException("dep"); 
>    this.dep = dep; 
> 
>    OnInitialize(); 
>   } 
> 
>   public dep DepProperty 
>   { 
>    get 
>    { 
>     return dep; 
>    } 
>   } 
>   protected abstract void OnInitialize(); 
>  } 

// adesso la tua costruttore della classe derivata non saranno costretti ad avere l'IDEP Parametro

class Derived : Base 
{ 
    public Derived() 
    { 

    } 

    protected override void OnInitialize() 
    { 
     // you can access the baseclass dependency Instance in this override 
     object depObject = this.DepProperty; 
    } 
} 
Problemi correlati