2017-02-22 3 views
0

Wir haben ein externes Projekt mit einer QCServiceLog-Klasse mit einer ILogging-Abhängigkeit, die von Unity aufgelöst wird. Aber QCServiceLog ist eine Singleton-Klasse, wie Sie im folgenden Beispiel sehen:Singleton-Klasse mit Abhängigkeitsinjektion C#

private readonly ILogging _logging = null; 

private static QCServiceLog _instance = null; 
public static QCServiceLog Instance 
{ 
    get 
    { 
     return _instance; 
    } 
} 

public QCServiceLog(ILogging logging) 
{ 
    _logging = logging; 
    if (_instance == null) 
    { 
     _instance = this; 
    } 
} 

Wir versuchen, es zu benutzen, und in unserer Lösung haben wir die Registrierung wie:

uc.RegisterType<ILogging, QCFileManager>(new ContainerControlledLifetimeManager()); 

Aber da QCServiceLog ist ein Singleton Wir glauben, dass der Code niemals durch den Konstruktor gelangt, dann wird _instance niemals instanziiert. Wir verwenden es dies zu tun:

QCServiceLog.Instance.Log(ex); 

Ist das Singleton korrekt umgesetzt? Wir glauben, dass es nie einen neuen von QCServiceLog macht.

Was denkst du? Können wir etwas tun, ohne das externe Projekt zu ändern? Die Ausnahme, wie Sie sich vorstellen können, ist:

Objektverweis nicht auf eine Instanz eines Objekts festgelegt.

Ich würde wirklich Ihre Hilfe schätzen!

Antwort

1

Ist dieser Singleton richtig implementiert?

Ja. Es muss jedoch zuerst aus dem Container instanziiert werden, bevor Sie eine statische Instanz davon erhalten können.

Mit anderen Worten: Sie können diese Zeile nicht verwenden:

QCServiceLog.Instance.Log(ex); 

, bis Sie ersten Anruf:

container.Resolve<QCServiceLog>(); 

(vorausgesetzt, Sie eine Instanz von ILogging mit Unity registriert haben), weil die ersten Der Aufruf wird den Konstruktor nicht erreichen, um den Wert _instance zu füllen.

Sie sind wahrscheinlich besser dran, entweder direkt injizieren, wo es gebraucht wird:

public class Foo(QCServiceLog log) 

Oder alternativ eine Wrapper-Klasse zu machen, die die Logik enthält es verkabeln richtig, bevor Sie es, die über Ihren DI-Container eingespritzt wird .

In jedem Fall sollten Sie beachten, dass DI in erster Linie für Ihre Anwendung ist. Dienstprogramme von Drittanbietern führen die Dinge nicht unbedingt DI-freundlich aus, daher müssen Sie möglicherweise facade oder adapter verwenden, um sie DI-freundlich für die Verwendung im Kontext Ihrer Anwendung zu machen.

1

Der Code, den Sie zur Verfügung gestellt haben, ist nicht Thread-sicher - einen Blick hier Implementing the Singleton Pattern in C# haben:

public QCServiceLog(ILogging logging) 
{ 
    _logging = logging; 
    if (_instance == null) 
    { 
     _instance = this; 
    } 
} 

Ein weiteres Problem ist, dass der Konstruktor nicht verborgen ist.Selbst wenn Ihr IoC-Container die Klasse als Singleton registriert, kann eine Instanz dieser Klasse unter Verwendung des Operators new immer noch an einer beliebigen Stelle im Code erstellt werden. Ich habe ein Speicherleck in einer App gefunden, an der ich gerade gearbeitet habe (Absicht war, über DI/IoC zu verwenden, das als Singleton registriert wurde, aber durch Code manuell neu aufgebaut wurde.

Verwandte Themen