2016-04-27 19 views
1

Dieser ist ein wenig kompliziert, also lesen Sie bitte alles durch. Ich arbeite an Code, der das MVVM-Muster für WPF implementiert. Ich habe eine XAML-Markup-Erweiterung, die nach einer bestimmten Eigenschaft im Datenkontext sucht. (Es ist eine lange und lustige Geschichte, aber außerhalb des Geltungsbereichs) Mein Ansichtsmodell wird als Dataconext in der Ansicht festgelegt.Inheritance dependency injection simplification

Hier ist ein Beispiel dafür, wie ich mein BaseViewmodel umgesetzt habe ...

public class ViewModelBase : IViewModelBase 
{ 
    protected CommandManagerHelper _commandManagerHelper; 

    //todo find a way of eliminating the need for this constructor 
    public OrionViewModelBase(CommandManagerHelper commandManagerHelper) 
    { 
     _commandManagerHelper = commandManagerHelper; 
    } 

    private IExampleService _exampleService; 

    public IExampleService ExampleService 
    { 
     get 
     { 
      if (_exampleService == null) 
      { 
       _exampleService = _commandManagerHelper.GetExampleService(); 
      } 

      return _exampleService; 
     } 
    } 
} 

Was dort passiert ist, dass ich die _exampleService effektiv verzögertes Laden bin. Ich bin mir sicher, dass es möglich ist, Lazy zu benutzen, aber ich bin noch nicht dazu gekommen, das zu implementieren.

Mein Xaml-Markup sucht und nutzt meinen Beispielservice, der auch von Code innerhalb des Ansichtsmodells verwendet werden könnte. Es wird überall in der Anwendung verwendet werden.

Ein Punkt zu beachten ist, dass meine Anwendung nur eine Instanz von ExampleServer hat, die herumgereicht werden, GetExampleService von überall in der Anwendung ruft die gleiche Instanz des Objekts zurückgeben. Es gibt nur eine Instanz des ExampleService-Objekts, obwohl es nicht als Singleton codiert ist. Hier

ist ein Beispiel dafür, wie ich von meinem ViewModelBase bin vererben ...

internal class ReportingViewmodel : ViewModelBase 
{ 
    private readonly IReportingRepository _reportingRepository; 

    public ReportingViewmodel(CommandManagerHelper commandManagerHelper, IReportingRepository reportingRepository) : base(commandManagerHelper) 
    { 
     _reportingRepository = reportingRepository; 
    } 
} 

Dieser Code funktioniert und funktioniert super. Allerdings muss jedesmal, wenn ich ein neues geerbtes Member der ViewModelBase implementiere, ": base (commandManagerHelper)" fehleranfällig sein. Ich habe wahrscheinlich 100 von diesen Implementierungen und jeder muss richtig sein.

Was ich mich wundere ist .... gibt es eine Möglichkeit, das gleiche Verhalten in Bezug auf die SOLID-Prinzipien zu implementieren und den Basiskonstruktor nicht jedes Mal aufrufen zu müssen, wenn ich eine Instanz der ViewModelBase implementiere?

das heißt würde Ich mag die ReportingViewModel wie diese

internal class ReportingViewmodel : ViewModelBase 
{ 
    private readonly IReportingRepository _reportingRepository; 

    public ReportingViewmodel(IReportingRepository reportingRepository) 
    { 
     _reportingRepository = reportingRepository; 
    } 
} 

aussehen, aber immer noch die ExampleService korrekt aufgefüllt.

Ich überlege gerade, das Service-Locator-Muster dafür zu verwenden, ich überlege auch, ein Singleton zu verwenden und bin offen für andere bessere Lösungen.

Der Grund, dass ich die Frage stelle, anstatt mit Code einzutauchen ist, dass ich weiß, dass der Singleton allgemein ein Anti-Muster ist, für mich bedeutet es, dass etwas anderes im Code falsch ist. Ich habe gerade einen Artikel über IoC gelesen und es ist das Service Locator Muster hier ist der Artikel http://www.devtrends.co.uk/blog/how-not-to-do-dependency-injection-the-static-or-singleton-container.

Antwort

2

Sie können den Basiskonstruktor nicht aufrufen. Es spielt keine Rolle, dass IExampleService nur einmal instanziiert und geteilt wird. Ihre ViewModelBase "weiß" das nicht (und sollte nicht). Alles, was es wissen muss, ist, dass das, was injiziert wird, diese Schnittstelle implementiert. Das ist einer der großen Vorteile, denn wenn Sie Testklassen testen, können Sie eine verspottete Version dieser Schnittstelle einfügen. Wenn Klassen von einer statischen Referenz auf etwas abhängen würden, das in einer Basisklasse vergraben ist, wäre es nicht möglich, sie durch einen Schein zum Testen zu ersetzen.

Ich verwende ReSharper. (Darf ich das sagen? Ich will nicht werben.) Neben vielen anderen Dingen erzeugt es diese Basiskonstruktoren für Sie.Ich bin mir sicher, irgendwann muss das in Visual Studio eingebaut werden.

+0

Ich benutze auch ReSharper. : D Ich suche nach der besten Implementierung dieser Lösung. –

+0

Ich nehme an, es gibt einen anderen Teil des Problems. Ich habe eine Ansicht, die meine benutzerdefinierte Markup-Erweiterung verwendet und die Ansichten datekontext festgelegt haben muss, obwohl die Ansicht kein Ansichtsmodell erfordert (es ist ein einfacher Anzeigedialog). Das Markup muss über den IExampleService und nicht über die Ansicht verfügen. Ist es immer noch richtig, ein ganzes Viewmodel zu erstellen? Oder ist es in Ordnung, die Markup ziehen die Erweiterung von woanders? (Wenn es in Ordnung ist, bedeutet das, dass ich die Art und Weise ändern kann, wie die Viewmodels zusammengesetzt sind). Ich muss nur herausfinden, wie es geht. –

+0

Bei Betrachtung ist die Frage, ob die Markup-Erweiterung ohne Viewmodel funktioniert, ein weiteres Thema. –