2010-04-19 12 views
11

Ho bisogno di memorizzare un gruppo di variabili a cui è necessario accedere a livello globale e mi chiedo se un modello singleton sarebbe applicabile. Dagli esempi che ho visto, un modello singleton è solo una classe statica che non può essere ereditata. Ma gli esempi che ho visto sono eccessivamente complessi per le mie esigenze. Quale sarebbe la classe di singleton più semplice? Non potrei semplicemente creare una classe statica, sigillata con alcune variabili all'interno?Singleton Pattern per C#

risposta

30

Tipicamente un Singleton non è una classe statica - un singleton vi darà una singola istanza di una classe.

Non so che cosa gli esempi che hai visto, ma di solito il singleton pattern può essere davvero semplice in C#:

public sealed class Singleton 
{ 
    private static readonly Singleton instance = new Singleton(); 
    static Singleton() {} // Make sure it's truly lazy 
    private Singleton() {} // Prevent instantiation outside 

    public static Singleton Instance { get { return instance; } } 
} 

Questo non è difficile.

Il vantaggio di un singleton rispetto ai membri statici è che la classe può implementare interfacce, ecc. Talvolta è utile, ma altre volte, i membri statici farebbero altrettanto bene. Inoltre, di solito è più facile passare da un singleton a un non singleton in seguito, ad es. passare il singleton come oggetto di "configurazione" alle classi di dipendenza, piuttosto che quelle classi di dipendenza che effettuano chiamate dirette statiche.

Personalmente cerco di evitare l'uso di singleton, laddove possibile, rendono i test più difficili, a parte qualsiasi altra cosa. A volte possono essere utili.

+0

Fantastica spiegazione .... Puoi dirci un'istanza (in tempo reale) in cui potresti trovare utile il modello singleton? +1 – Raja

+0

@Raja: Non riesco a pensare ad alcuna situazione genuina al minuto, sebbene ciò non significhi che non ne ho usato nessuno. –

+0

@Raja questo è qualcosa che userò molto in .NET 4.0 nelle mie classi che fanno qualsiasi riflessione 'statico privato readonly ConcurrentDictionary _reflectionCache = new ConcurrentDictionary();' –

4

Un Singleton non è solo una classe statica che non può essere ereditata. È una classe normale che può essere istanziata una sola volta, con tutti che condividono quella singola istanza (e renderla thread-safe è ancora più lavoro).

Il tipico codice .NET per un Singleton è simile al seguente. Questo è un esempio veloce, e non con qualsiasi mezzo la migliore implementazione o thread-safe codice:

public sealed class Singleton 
{ 
    Singleton _instance = null; 

    public Singleton Instance 
    { 
     get 
     { 
      if(_instance == null) 
       _instance = new Singleton(); 

      return _instance; 
     } 
    } 

    // Default private constructor so only we can instanctiate 
    private Singleton() { } 

    // Default private static constructor 
    private static Singleton() { } 
} 

Se avete intenzione di andare giù per il sentiero che stai pensando, una classe statica sigillato funzionerà va bene.

+0

Penso che sia necessario rivedere quel codice un po '- e se non si presta attenzione nella revisione, non sarà sicuro per i thread. Tuttavia, renderlo thread-safe è davvero abbastanza facile. –

+0

@Jon Non avevo intenzione di usare la versione thread-safe qui. Esempio veloce Conosco un modo per renderlo thread-safe, ma sarei interessato a conoscere le altre revisioni (solo per curiosità). –

0

Quindi, per quanto mi riguarda, questa è l'implementazione più concisa e semplice del modello Singleton in C#.

http://blueonionsoftware.com/blog.aspx?p=c6e72c38-2839-4696-990a-3fbf9b2b0ba4

Vorrei, tuttavia, suggerisco di single sono davvero brutte modelli ... io considero loro di essere un anti-modello.

http://blogs.msdn.com/scottdensmore/archive/2004/05/25/140827.aspx

Per quanto mi riguarda, preferisco avere qualcosa di simile a un repository, attuazione IRepository. La classe può dichiarare la dipendenza al IRepository nel costruttore e può essere superato utilizzando Dependency Injection o uno dei seguenti metodi:

http://houseofbilz.com/archive/2009/05/02.aspx

7

Ci sono diversi modelli che potrebbero essere appropriato per voi, un Singleton è uno di peggio.

Registro

struct Data { 
    public String ProgramName; 
    public String Parameters; 
} 

class FooRegistry { 
    private static Dictionary<String, Data> registry = new Dictionary<String, Data>(); 
    public static void Register(String key, Data data) { 
    FooRegistry.registry[key] = data; 
    } 
    public static void Get(String key) { 
    // Omitted: Check if key exists 
    return FooRegistry.registry[key]; 
    } 
} 

Vantaggi

  • facile passare a un oggetto fittizio per test automatizzati
  • È ancora possibile memorizzare più istanze, ma, se necessario, si dispone di una sola istanza .

Svantaggi

  • Leggermente più lento di un singolo o una variabile globale

classe Static

class GlobalStuff { 
    public static String ProgramName {get;set;} 
    public static String Parameters {get;set;} 
    private GlobalStuff() {} 
} 

Vantaggi

  • semplice
  • veloce

Svantaggi

  • Difficile passare dinamicamente a IE un oggetto fittizio
  • rigido per passare ad un altro tipo di oggetto, se i requisiti cambiano

semplice Singleton

class DataSingleton { 
    private static DataSingleton instance = null; 
    private DataSingleton() {] 
    public static DataSingleton Instance { 
    get { 
     if (DataSingleton.instance == null) DataSingleton.instance = new DataSingleton(); 
     return DataSingleton; 
    } 
    } 
} 

Vantaggi

  • Nessuno in realtà

Svantaggi

  • Difficile creare un singleton a prova di thread, la precedente versione si guasta se più thread accedono all'istanza.
  • rigido per passare da un oggetto fittizio

Personalmente come il modello Registry ma YMMV.

Dovresti dare un'occhiata a Dependency Injection perché di solito è considerata la migliore pratica, ma è un argomento troppo grande da spiegare qui.

http://en.wikipedia.org/wiki/Dependency_Injection

+0

Penso che il tuo modello singleton sia sbagliato, che se il controllo all'interno del getter non è thread-safe. Si desidera implementare un singleton come descritto sopra da @Jon Skeet. Teoricamente, 2 thread potrebbero entrare in quel getter allo stesso tempo, entrambi vedono istanza == null e quindi eseguono entrambi la seconda linea causando la mutilazione del singleton dall'ultimo thread out. –

+0

@Chris: ho menzionato che questa implementazione non è protetta da errori nella sezione "Svantaggi". Il Codice è lì per spiegare il concetto, non per dare un esempio pienamente funzionante. – dbemerlin

+0

@dbemerlin, correggi il codice per FooRegistry, public static ** Data ** Get (chiave String) invece di _void_. E davvero grazie per la bella panoramica. –

-1

Usando le caratteristiche del linguaggio. Per lo più semplice implementazione thread-safe è:

public sealed class Singleton 
{ 
    private static readonly Singleton _instance; 

    private Singleton() { } 

    static Singleton() 
    { 
     _instance = new Singleton(); 
    } 

    public static Singleton Instance 
    { 
     get { return _instance; } 
    } 
} 
2

con C# 6 Inizializzatori Auto-proprietà.

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

Breve e pulito - Sarò felice di sentire i lati negativi.

+1

per i principianti non è thread-safe – JerryGoyal