public sealed class Singleton
{
Singleton() {}
public static Singleton Instance
{
get
{
return Nested.instance;
}
}
class Nested
{
// Explicit static constructor to tell C# compiler
// not to mark type as beforefieldinit
static Nested() {}
internal static readonly Singleton instance = new Singleton();
}
}
Ich möchte das Singleton-Muster von Jon Skeet in meiner aktuellen Anwendung in C # implementieren .
Ich habe zwei Zweifel am Code
Wie ist es möglich, auf die äußere Klasse innerhalb einer verschachtelten Klasse zuzugreifen? ich meine
internal static readonly Singleton instance = new Singleton();
Wird so etwas als Schließung bezeichnet?
Ich kann diesen Kommentar nicht verstehen
// Explicit static constructor to tell C# compiler // not to mark type as beforefieldinit
Was schlägt uns dieser Kommentar vor?
c#
.net
design-patterns
architecture
singleton
Amutha
quelle
quelle
Antworten:
Nein, das hat nichts mit Verschlüssen zu tun. Eine verschachtelte Klasse hat Zugriff auf die privaten Mitglieder ihrer äußeren Klasse, einschließlich des privaten Konstruktors hier.
Lesen Sie meinen Artikel auf beforefieldinit . Möglicherweise möchten Sie den statischen No-Op-Konstruktor oder nicht - dies hängt davon ab, welche Faulheit Sie benötigen. Sie sollten sich bewusst sein, dass .NET 4 die tatsächliche Semantik der Typinitialisierung etwas ändert (immer noch innerhalb der Spezifikation, aber fauler als zuvor).
Benötigen Sie dieses Muster wirklich ? Sind Sie sicher, dass Sie nicht durchkommen können mit:
quelle
Lazy<T>
damit Sie keinen statischen Konstruktor für den magischenBeforeFieldInit
Nebeneffekt deklarieren müssen ?FieldBeforeInit
istMahaBharata
vonMicrosoft
Zu Frage (1): Die Antwort von Jon ist richtig, da er die Klasse 'Verschachtelt' implizit als privat markiert, indem er sie nicht öffentlich oder intern macht :-). Sie können dies auch explizit tun, indem Sie 'privat' hinzufügen:
Zu Frage (2): im Grunde , was die Post über beforeinitfield und Typ Initialisierung Sie sagen , ist , dass , wenn Sie keine statische Konstruktor haben, kann die Laufzeit es jederzeit initialisiert werden (aber , bevor Sie es verwenden). Wenn Sie einen statischen Konstruktor haben, initialisiert Ihr Code im statischen Konstruktor möglicherweise die Felder. Dies bedeutet, dass die Laufzeit das Feld nur initialisieren darf, wenn Sie nach dem Typ fragen.
Wenn Sie also nicht möchten, dass die Laufzeitfelder "proaktiv" initialisiert, bevor Sie sie verwenden, fügen Sie einen statischen Konstruktor hinzu.
So oder so, wenn Sie Singletons implementieren, möchten Sie entweder, dass es so faul wie möglich initialisiert wird und nicht, wenn die Laufzeit denkt, dass es Ihre Variable initialisieren sollte - oder es ist Ihnen wahrscheinlich einfach egal. Aufgrund Ihrer Frage möchten Sie sie vermutlich so spät wie möglich.
Das bringt Jons Beitrag über Singletons auf den Punkt, der IMO das zugrunde liegende Thema dieser Frage ist. Oh und die Zweifel :-)
Ich möchte darauf hinweisen, dass sein Singleton # 3, den er als "falsch" markiert hat, tatsächlich korrekt ist (da Sperren beim Beenden automatisch eine Speicherbarriere implizieren ). Es sollte auch schneller als Singleton # 2 sein, wenn Sie die Instanz mehr als einmal verwenden (was mehr oder weniger der Sinn eines Singletons ist :-)). Wenn Sie also wirklich eine faule Singleton-Implementierung benötigen, würde ich mich wahrscheinlich für diese entscheiden - aus den einfachen Gründen, dass (1) es für jeden, der Ihren Code liest, sehr klar ist, was los ist, und (2) Sie wissen, was passieren wird mit Ausnahmen.
Falls Sie sich fragen: Ich würde niemals Singleton Nr. 6 verwenden, da dies mit Ausnahmen leicht zu Deadlocks und unerwartetem Verhalten führen kann. Weitere Informationen finden Sie unter: Lazys Sperrmodus , insbesondere ExecutionAndPublication.
quelle
Regarding question (1): The answer from Jon is correct ...
Jon Skeet hat immer Recht ...