Chiarimento Singleton di Jon Skeet


214
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();
    }
}

Vorrei implementare il modello Singleton di Jon Skeet nella mia attuale applicazione in C #.

Ho due dubbi sul codice

  1. Come è possibile accedere alla classe esterna all'interno della classe nidificata? intendo

    internal static readonly Singleton instance = new Singleton();

    Qualcosa si chiama chiusura?

  2. Non riesco a capire questo commento

    // Explicit static constructor to tell C# compiler
    // not to mark type as beforefieldinit

    cosa ci suggerisce questo commento?


12
ahah pensavo di aver detto che era un po 'preoccupato lol ... si è rivelato essere un John Nolan diverso
John Antony Daniel Nolan

14
Due cose sono universalmente accettate: il sole sorge da est e Jon Skeet ha sempre ragione. Ma non sono ancora sicuro del primo: P
akhil_mittal,

2
@ thepirat000 - Se fosse solo un partecipante a SO / Meta, potrei non essere d'accordo, ma ha abbastanza influenza nel mondo reale della programmazione che potrebbe essere effettivamente legittimo - Sono sicuro che qualcuno l'ha creato in un punto o nell'altro .
Codice Jockey

8
La tassonomia di questa domanda è in discussione su meta .
BoltClock

Risposte:


359
  1. No, questo non ha nulla a che fare con le chiusure. Una classe nidificata ha accesso ai membri privati ​​della sua classe esterna, incluso il costruttore privato qui.

  2. Leggi il mio articolo su beforefieldinit . Potresti o non vuoi il costruttore statico no-op - dipende da quale pigrizia ti garantisce. È necessario essere consapevoli che .NET 4 cambia le effettive tipo di inizializzazione semantica in qualche modo (ancora all'interno le specifiche, ma più pigri rispetto a prima).

Hai davvero bisogno di questo modello però? Sei sicuro di non riuscire a cavartela con:

public sealed class Singleton
{
    private static readonly Singleton instance = new Singleton();
    public static Singleton Instance { get { return instance; } }

    static Singleton() {}
    private Singleton() {}
}

12
@Anindya: No, va bene. Potresti voler inviare JetBrains per lamentarti però :)
Jon Skeet,

2
@JonSkeet, ho appena sollevato una preoccupazione per JetBrains al riguardo (# RSRP-274373). Vediamo cosa possono inventare. :)
Anindya Chatterjee,

3
@Moons: No. Un singleton vive per la durata di AppDomain.
Jon Skeet,

2
@JonSkeet Qualche motivo per non usarlo in Lazy<T>modo da non dover dichiarare un costruttore statico per l' BeforeFieldIniteffetto magico magico ?
Ed T

3
FieldBeforeInitè MahaBharatadiMicrosoft
Amit Kumar Ghosh,

49

Per quanto riguarda la domanda (1): la risposta di Jon è corretta, dal momento che segna implicitamente la classe "Annidata" privata non rendendola pubblica o interna :-). Puoi anche farlo esplicitamente aggiungendo "privato":

    private class Nested

Per quanto riguarda la domanda (2): sostanzialmente ciò che ti dice il post su beforeinitfield e l' inizializzazione del tipo è che se non hai un costruttore statico, il runtime può inizializzarlo in qualsiasi momento (ma prima di usarlo). Se si dispone di un costruttore statico, il codice nel costruttore statico potrebbe inizializzare i campi, il che significa che al runtime è consentito inizializzare il campo solo quando si richiede il tipo.

Quindi, se non si desidera che il runtime inizializzi i campi 'in modo proattivo' prima di utilizzarli, aggiungere un costruttore statico.

In entrambi i casi, se stai implementando i singoli punti o vuoi che inizializzi il più pigro possibile e non quando il runtime pensa che dovrebbe inizializzare la tua variabile - o probabilmente non ti interessa. Dalla tua domanda suppongo che li desideri il più tardi possibile.

Ciò porta a incontrare il post di Jon sul tema di Singleton , che è l'IMO il tema alla base di questa domanda. Oh e i dubbi :-)

Vorrei sottolineare che il suo singleton n. 3, che ha contrassegnato come "sbagliato", è in realtà corretto (perché il blocco implica automaticamente una barriera di memoria all'uscita ). Dovrebbe anche essere più veloce di singleton # 2 quando usi l'istanza più di una volta (che è più o meno il punto di un singleton :-)). Quindi, se hai davvero bisogno di un'implementazione pigra di singleton, probabilmente lo farei per quello - per i semplici motivi che (1) è molto chiaro per tutti coloro che leggono il tuo codice cosa sta succedendo e (2) sai cosa accadrà con eccezioni.

Nel caso ti stia chiedendo: non userei mai singleton # 6 perché può facilmente portare a deadlock e comportamenti imprevisti con eccezioni. Per i dettagli, consultare: modalità di blocco di pigro , in particolare ExecutionAndPublication.


62
Regarding question (1): The answer from Jon is correct ...Jon Skeet ha sempre ragione ....
Noctis,

72
Punti extra per tentare una risposta su una domanda di Jon Skeet a cui Jon Skeet ha già risposto.
valdetero,

8
@valdetero Hahaha. Questo ... hahaha +1
akinuri
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.