7

Ich habe eine Basisklasse Basis dependecy Dep und Ausfall- und Injection Constructor-Implizit Abhängigkeit in Basisklasse Injektion während abgeleiteten Klasse durch Unity behoben ist

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

Ich dachte mit, dass Dependency dep automatisch (durch Constructor erhalten injiziert sollte Injektion), wenn die abgeleitete Klasse aufgelöst wird.

Aber das scheint nicht zu funktionieren, wenn ich eine Klasse von ihm ableite und diese Klasse auflöse, stattdessen wird ein Standard-Konstruktor der Basis aufgerufen.

Ich kann nur funktionieren, wenn ich den Konstruktor explizit von der abgeleiteten Klasse aufrufen.

class Derived : Base 
{ 

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

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

Bietet Einheit eine direkte Art und Weise implizit die Injektion Constructor der Basisklasse aufrufen, (nicht durch explizite Construtor Anruf)? Wenn nicht, gibt es einen Grund, warum Einheit Container nicht selbst tut?

+0

Ihre Probleme, die durch mehrere Konstruktoren haben. Ihre Dienste sollten nur einen einzigen Konstruktor haben. [Mehrere Konstruktoren zu haben ist ein Anti-Pattern] (https://www.cuttingedge.it/blogs/steven/pivot/entry.php?id=97) und sollte vermieden werden. – Steven

+0

@Steven Ich habe Ihren Standpunkt, dass mehrere Konstruktoren ein Anti-Muster ist. Aber das Entfernen des Standardkonstruktors löst den Zweck hier nicht auf. –

+0

Ich denke, es löst Ihre Probleme tatsächlich, denn wenn sowohl "Base" als auch "Derived" jeweils nur einen Konstruktor enthalten, der die erforderlichen Abhängigkeiten übernimmt, existiert das Problem überhaupt nicht. Ich stimme jedoch mit @BatteryBackupUnit überein, dass eine Basisklasse nicht das beste Design ist. – Steven

Antwort

11

Nein, Einheit ist nicht dazu in der Lage. Eigentlich gibt es keinen einzigen Container, der das kann. Ein Konstruktor ist da, um eine Klasse zu instanziieren. Wenn Sie zwei Konstruktoren aufrufen, erhalten Sie zwei Instanzen. Wenn die Basisklasse abstrakt ist, könnten Sie nicht einmal ihren Konstruktor aufrufen (außer abgeleitete Konstruktoren, wie Sie wissen). Wenn Sie also die Konstruktorinjektion verwenden möchten, funktioniert es nur, wenn Sie den Wert explizit in den Konstruktor Derived eingeben, der den nicht standardmäßigen Konstruktor Base aufruft.

Sie können jedoch stattdessen auch die Injektion von Eigenschaften oder Methoden verwenden. Mit diesen müssen Sie die Abhängigkeit nicht zu jedem Konstruktor einer abgeleiteten Klasse hinzufügen.

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

Bitte beachten Sie:

  • Das Objekt instanziiert wird (Ctor Injektion) vor dem Verfahren/Eigenschaft Einspritzung durchgeführt
  • Es könnte angemessen sein, das Design anzupassen, nicht eine Basisklasse benötigen, Composition over Inheritance
3

Dies ist zu sehen, wie Sie das Problem lösen sollen:

class abstract Base : IBase 
{ 
    private readonly IDep dep; 

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

Jetzt ist Ihre Basisklasse hat nur einen Konstruktor und dieser Konstruktor definiert alle Abhängigkeiten, die die Klasse benötigt. Es gibt nur eine Möglichkeit, diese Klasse zu erstellen, und die Klasse schützt ihre Invarianten. Die Abhängigkeit ist Stellen in einem privaten Feld, da andere Klassen keinen Zugriff auf diese Abhängigkeit haben.

Mit dieser Basisklasse wird die abgeleitete Klasse wie folgt aussehen:

class Derived : Base 
{ 
    private readonly IDep dep; 

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

Hier die abgeleitete Klasse hat auch einen einzigen Konstruktor definieren die Abhängigkeiten dieser Klasse erfordert. Es kann nicht auf andere Weise erstellt werden. Falls die Klasse die Abhängigkeit selbst verwendet, sollte sie die Abhängigkeit in einem privaten Feld zur späteren Verwendung speichern. Da diese Klasse nur einen Konstruktor hat, gibt es keine Zweideutigkeit in dem Aufruf des Konstruktors, und es gibt keinen Grund, den Konstruktor mit einem [InjectionConstructor] -Attribut zu markieren.

Beachten Sie, dass ich mit BatteryBackupUnit einverstanden bin. Da ich Dependency Injection und die SOLID-Prinzipien auf meine Anwendungen anwende, sehe ich wenig Grund mehr, Basisklassen zu verwenden. Die Verwendung von Komposition statt Vererbung reduziert oft die Komplexität des Systems.

+0

Ja, ich kann das so machen. Aber mein Fokus lag nicht auf expliziten Konstruktoraufrufen (: base (dep)), und ja, für mehrere Konstruktoren stimme ich dir zu, dass ich mehrere Konstruktoren vermeiden sollte. Ich stimme mit BatteryBackupUnit überein, dass Einheit den Injection Constructor nicht implizit aufrufen kann, da es Beschränkungen von C# ist .net –

+0

Ich würde 'dep 'als' protected readonly 'in der Basisklasse deklarieren. Der Modifikator "protected" ermöglicht abgeleiteten Klassen den Zugriff auf "dep", während "readonly" Änderungen daran verhindert. Dies macht eine Verdopplung der dep-Variablen und ihre Initialisierung in der abgeleiteten Klasse überflüssig. –

0

Einfache und unkomplizierte Lösung ist ein "InjectionMethod" in Ihrer Basisklasse.

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

// jetzt Ihre abgeleitete Klasse Constructor der idep Parameter nicht gezwungen sein, haben sind

class Derived : Base 
{ 
    public Derived() 
    { 

    } 

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