7 Stimmen

Frage zu nicht-statischen Mitgliedern eines Singletons (C#)

Ich habe eine Frage zu Singletons, von der ich denke, dass ich die Antwort darauf kenne... aber jedes Mal, wenn das Szenario auftaucht, habe ich irgendwie Zweifel an mir selbst, also würde ich gerne die konkrete Antwort wissen.

Sagen wir, ich habe zwei Klassen, die wie folgt eingerichtet sind...

 public class ClassA
 {
     private static ClassA _classA;

     public static ClassA Instance { get { return _classA ?? LoadClassA(); } }

     private ClassA(){}

     public static ClassA LoadClassA()
     {
         _classA = new ClassA();
         return _classA;
     }

     private ClassB _classB = new ClassB();

     public ClassB ClassB { get { return _classB; } set { _classB = value; } }
 }

 public class ClassB
 {
 }

Meine Frage ist einfach.

Ich frage mich, ob das Feld _classB auch als statisch behandelt wird, wenn ich auf das Singleton für ClassA zugreife? Auch wenn ich _classB nicht als statisches Mitglied deklariert habe.

Ich habe immer nur vermutet, dass _classB als statisch behandelt wird (ein Speicherplatz), aber ich würde es gerne genau wissen. Liege ich falsch? Wird für _classB jedes Mal ein neues Objekt erstellt, wenn man von der Singleton-KlasseA darauf zugreift, obwohl es nur eine KlasseA im Speicher gibt? Oder liegt es daran, dass ich _classB bei der Deklaration neu angelegt habe, was dazu führt, dass es nur eine Instanz von _classB gibt?

Vielen Dank im Voraus, -Matt

11voto

Reed Copsey Punkte 536986

Wenn Sie ein Singleton erstellen, erstellen Sie eine einzelne statische Instanz eines nicht-statischen Typs.

In diesem Fall enthält Ihr Typ (Klasse A) einen Verweis auf einen anderen Typ (Klasse B). Die statische Instanz enthält einen einzigen Verweis auf eine einzelne Instanz eines Objekts der Klasse B. Technisch gesehen ist sie nicht "statisch", aber da sie auf ein statisches Objekt (die Instanz der Klasse A) verweist, verhält sie sich wie eine statische Variable. Es gibt immer nur ein einziges Objekt der Klasse B (auf das die Instanz der Klasse A zeigt). Sie werden nie mehr als eine Instanz der Klasse B erstellen. aus dem Bereich der Klasse A.

Es spricht jedoch nichts dagegen, eine zweite Instanz der Klasse B an anderer Stelle zu erzeugen - dies wäre dann eine andere Instanz.

3voto

Michael Petrotta Punkte 58361

_classB ist ein (nicht statisches) Instanzmitglied von ClassA. Jede Instanz von ClassA hat eine Instanz von _classB (angesichts des Feldinitialisierers, den Sie geschrieben haben). Wenn Sie also das Singleton-Muster verwenden, um auf ClassA zuzugreifen, und somit immer (höchstens) eine Instanz von ClassA geladen haben, haben Sie immer (höchstens) eine Instanz von ClassB, die über ClassA geladen wurde.

Da die KlasseB einen öffentlichen Standardkonstruktor hat, kann es sein, dass etwas anderes, das weit entfernt ist, von sich aus Instanzen erzeugt. Wenn das ein Problem ist, sollten Sie ClassB als private Klasse definieren. Da ClassA einen öffentlichen Standardkonstruktor hat, hindert nichts die Leute daran, so viele Instanzen zu erstellen, wie sie wollen. Sie könnten den no-arg-Konstruktor privat machen:

private ClassA() {}

2voto

Noldorin Punkte 138548

Das Singleton-Muster stellt sicher, dass nur eine Instanz von ClassB ist zugänglich von der Singleton-Instanz von ClassA zu jeder Zeit. Der Sinn des Singleton-Musters ist, dass es garantiert nur eine Instanz de ClassA ist jederzeit verfügbar, so dass nur ein Verweis auf _classB (da jedoch ClassA veränderbar ist, kann sich diese Referenz ändern).

Beachten Sie jedoch, dass die Umfang de ClassB ist immer noch auf Instanz-Ebene und nicht auf statischer Ebene. Der Compiler wird niemals etwas so Seltsames tun, dass sie einen anderen Bereichsbezeichner verwenden, als Sie angeben. Sie müssen immer noch auf den Verweis auf ClassB über eine Instanz, unabhängig davon, ob Sie ein Singleton verwenden oder nicht.

2voto

Joseph Punkte 24916

Indem Sie Ihre Erklärung so formulieren:

private ClassB _classB = new ClassB();

Sie instanziieren _classB zu einer neuen Instanz von ClassB, wenn der Konstruktor von ClassA aufgerufen wird.

Bei einem Singleton-Muster ist die einzige Möglichkeit, den Konstruktor von ClassA aufzurufen, die Verwendung einer statischen Methode (in Ihrem Fall über die Instance-Eigenschaft), die effektiv sicherstellt, dass nur eine ClassA erstellt wird.

Dadurch wird sichergestellt, dass _classB nur einmal neu angelegt wird, aber nicht statisch ist. Wenn jedoch jemand ClassA so verändert, dass es in Zukunft kein Singleton mehr ist, dann würden Sie mehrere Instanzen von ClassB erzeugen. Wenn _classB wirklich statisch wäre, wäre dies nicht der Fall.

1voto

Darin Dimitrov Punkte 990883

Wie definiert, verstößt ClassA gegen die Definition für Singleton. Stellen Sie sich vor, zwei Threads rufen gleichzeitig die statische Instance-Eigenschaft auf. Da der Zugriff nicht synchronisiert ist, könnten Sie zwei verschiedene Instanzen von ClassA und damit zwei verschiedene Instanzen von ClassB erhalten.

  1. Thread1 ruft die Instance-Eigenschaft auf, und da _classA null ist, wird die LoadClassA-Methode aufgerufen
  2. Thread2 ruft die Instance-Eigenschaft auf, und da _classA noch null ist, wird die LoadClassA-Methode aufgerufen
  3. Thread1 und Thread2 erhalten zwei verschiedene Instanzen von ClassA

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X