Frage zu nicht statischen Membern eines Singletons (C #)

7

Ich habe eine Frage zu Singletons, von denen ich denke, dass ich die Antwort kenne ... aber jedes Mal, wenn das Szenario auftaucht, achte ich mich ein wenig selbst, damit ich die konkrete Antwort wissen möchte.

Sagen wir, ich habe zwei Klassen als so eingerichtet ...

%Vor%

Meine Frage ist einfach.

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

Ich habe immer im Grunde nur erraten, dass _classB es als statisch (ein Speicherort) behandelt wird, aber ich würde gerne sicher wissen. Liege ich falsch? Wird jedes Mal ein neues Objekt für _classB erstellt, wenn Sie von Singleton ClassA darauf zugreifen ... obwohl nur ein ClassA im Speicher vorhanden ist? Oder liegt es daran, dass ich _classB bei der Deklaration, die bewirkt, dass es nur eine Instanz gibt, neu erstellt habe?

Vielen Dank im Voraus, -Matt

    
matt_dev 06.07.2009, 17:43
quelle

9 Antworten

11

Wenn Sie einen 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 einzelnen Verweis auf eine einzelne Instanz eines Klasse-B-Objekts. Technisch gesehen ist es nicht "statisch", aber da es zu einem statischen Objekt (der Instanz der Klasse A) verwurzelt ist, verhält es sich wie eine statische Variable. Sie haben immer ein und nur ein Klasse-B-Objekt (auf das von Ihrer Klasse-A-Instanz verwiesen wird). Sie werden nie mehr als eine Klasse B-Instanz innerhalb der Klasse A erstellen.

Es besteht jedoch keine Gefahr, dass eine zweite Instanz der Klasse B an anderer Stelle erzeugt wird - dies wäre eine andere Instanz.

    
Reed Copsey 06.07.2009, 17:49
quelle
3

_classB ist ein Instanzenelement (nicht statisch) 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 über ClassA geladen.

Da ClassB jetzt einen öffentlichen Standardkonstruktor hat, kann etwas anderes in der Ferne Instanzen selbst erstellen. Wenn dies ein Problem ist, sollten Sie die ClassB-Klasse als privat betrachten. Da ClassA über einen öffentlichen Standardkonstruktor verfügt, verhindert auch nichts, dass Benutzer beliebig viele Instanzen erstellen können. Sie könnten den Konstruktor no-arg als privat setzen:

%Vor%     
Michael Petrotta 06.07.2009 17:48
quelle
2

Das Singleton-Muster stellt sicher, dass immer nur eine Instanz von ClassB von der Singleton-Instanz von ClassA aus auf zugreifbar ist. Der springende Punkt des Singleton-Patterns ist, dass es garantiert, dass nur eine Instanz von ClassA jederzeit verfügbar ist, also nur eine Referenz auf _classB (obwohl da ClassA veränderbar ist, diese Referenz kann ändern).

Beachten Sie jedoch, dass der Bereich von ClassB immer noch auf Instanzebene und nicht auf statischer Ebene ist. Der Compiler wird nie etwas so seltsames tun, um einen anderen Bereichsspezifizierer zu verwenden, als Sie angeben. Sie müssen immer noch auf den Verweis auf ClassB über eine Instanz zugreifen, unabhängig davon, ob Sie ein Singleton verwenden oder nicht.

    
Noldorin 06.07.2009 17:48
quelle
2

Indem Sie Ihre Erklärung wie folgt haben:

%Vor%

Sie implementieren _classB immer dann in eine neue Instanz von ClassB, wenn der Konstruktor von ClassA aufgerufen wird.

Bei einem Singleton-Muster ist der einzige Aufruf des Konstruktors von ClassA die Verwendung einer statischen Methode (in Ihrem Fall durch die Instance-Eigenschaft), wodurch sichergestellt wird, dass nur ein ClassA erstellt wird.

Dies stellt sicher, dass _classB nur einmal aktualisiert wird, aber es ist nicht statisch. Wenn jedoch jemand in der Zukunft ClassA geändert hat, um kein Singleton mehr zu sein, würden Sie mehrere Instanzen von ClassB erstellen. Wenn _classB wirklich statisch wäre, wäre das nicht der Fall.

    
Joseph 06.07.2009 17:49
quelle
1

Wie definiert, verletzt ClassA die Definition für Singleton. Stellen Sie sich vor, dass zwei Threads gleichzeitig die statische Instance-Eigenschaft aufrufen. Da der Zugriff nicht synchronisiert ist, könnten Sie mit zwei verschiedenen Instanzen von ClassA und damit zwei verschiedenen Instanzen von ClassB kommen.

  1. Thread1 ruft die Instance-Eigenschaft auf und da _classA null ist, wird die LoadClassA-Methode
  2. eingegeben
  3. Thread2 ruft die Instance-Eigenschaft auf, und da _classA immer noch null ist, wird die LoadClassA-Methode
  4. aufgerufen
  5. Thread1 und Thread2 erhalten zwei verschiedene Instanzen von ClassA
Darin Dimitrov 06.07.2009 17:48
quelle
0

Markieren Sie ClassB einfach als statisch, wenn Sie nur eine Instanz haben möchten.

Meiner Meinung nach ist es immer besser, klaren Code zu schreiben, der Ihnen die vollen Absichten zeigt. Auf diese Weise muss die nächste Person, die an Ihrem Code arbeitet, kein Ratespiel spielen, um zu bestimmen, was Sie tun möchten.

    
Justin 06.07.2009 17:51
quelle
0

Da ClassA ein Singleton ist, gibt es in Ihrer Anwendung nur eine Instanz davon. Innerhalb dieser Klasseninstanz gibt es ein Member zum Speichern einer ClassB-Variablen. Sobald Sie diese Variable initialisiert haben, handelt es sich um eine Instanzvariable. Da Sie jedoch nur eine Instanz von ClassA haben, erhalten Sie immer dieselbe Instanz von ClassB.

Ich würde auch empfehlen, die interne Instanz nicht zu erstellen, da sie nicht threadsicher ist.

%Vor%

durch nicht faulen Laden, und sofort initialisieren, stellen Sie Threadsicherheit sicher.

    
NerdFury 06.07.2009 17:51
quelle
0

_classB ist nicht statisch; Eine Instanz von ClassA enthält einen Verweis auf eine Instanz von _classB; Wenn die Instanz von ClassA statisch ist (wie in der Singleton-Instanz), enthält sie immer noch einen Verweis auf _classB, aber neue Instanzen von ClassA enthalten DIFFERENT-Verweise auf (möglicherweise) verschiedene Instanzen von _classB. Wenn Sie also über das Singleton-Muster auf dieselbe Instanz von ClassA verweisen, erhalten Sie immer noch dieselbe Instanz von _classB; Wenn Sie jedoch eine neue Instanz von ClassA erstellen, erhalten Sie eine andere Instanz von _classB, weshalb _classB nicht statisch ist.

    
Paul Sonier 06.07.2009 17:54
quelle
0

Ich bin überrascht, dass niemand darauf hingewiesen hat, dass ClassB eine öffentliche Eigenschaft von ClassA bei einem öffentlichen Setter ist. Nichts hält jemanden davon ab etwas zu schreiben wie:

%Vor%

Dies würde die Instanz von ClassB löschen, die zum Zeitpunkt der Erstellung der Einzelinstanz von ClassA erstellt wurde, und würde sie durch die neu erstellte Instanz von ClassB ersetzen.

Ein verwandtes Szenario ist, dass solange _classB in einer abgeleiteten Klasse gesetzt werden kann (zB wenn der Setter für ClassB geschützt wurde), kann nicht garantiert werden, dass es nur eine einzige Instanz von% geben würde. co_de% immer.

Ich denke, der richtige Weg, um diese Art von Code zu schreiben, wäre, sowohl ClassB und ClassA als Singletons zu implementieren und ClassB zu einer inneren Klasse von ClassB zu machen (sonst hätten Sie 2 nicht zusammenhängende Klassen ClassA und ClassA mit einem Verweis auf ClassB verfügbar durch ClassB , was (in diesem Szenario) nicht von ClassA.Instance.ClassB abweichen würde.

Wenn ClassB.Instance nur innerhalb von ClassB instanziierbar ist, könnte es möglicherweise andere Instanzen von ClassA instanziierbar in einer abgeleiteten Klasse geben.

    
Umar Farooq Khawaja 10.06.2011 15:55
quelle