Domanda

Come posso implementare il modello singleton in C #? Voglio inserire le mie costanti e alcune funzioni di base mentre le uso ovunque nel mio progetto. Voglio averli "globali" e non ho bisogno di vincolarli manualmente a tutti gli oggetti che creo.

È stato utile?

Soluzione

Se stai solo memorizzando alcuni valori globali e hai alcuni metodi che non richiedono stato, non hai bisogno di singleton. Rendi statica la classe e le sue proprietà / metodi.

public static class GlobalSomething
{
   public static int NumberOfSomething { get; set; }

   public static string MangleString( string someValue )
   {
   }
}

Singleton è molto utile quando hai una classe normale con stato, ma ne vuoi solo una. I collegamenti forniti da altri dovrebbero essere utili per esplorare il modello Singleton.

Altri suggerimenti

Singleton! = Global . Sembra che tu stia cercando la parola chiave static .

I singoli hanno senso solo se entrambe sono vere:

  1. L'oggetto deve essere globale
  2. Deve esistere solo un'istanza singola dell'oggetto

Nota che # 2 non significa che ti piacerà l'oggetto abbia solo una singola istanza - in tal caso, istanzialo solo una volta - significa che lì deve (come in, è pericoloso per questo non essere vero) essere sempre e solo una singola istanza.

Se vuoi globale, basta creare un'istanza globale di un oggetto (non signleton) (o renderlo statico o altro). Se vuoi solo un'istanza, di nuovo, static è tuo amico. Inoltre, è sufficiente creare un'istanza di un solo oggetto.

Questa è comunque la mia opinione.

Puoi davvero semplificare un'implementazione singleton, questo è quello che uso:

    internal FooService() { }        
    static FooService() { }

    private static readonly FooService _instance = new FooService();

    public static FooService Instance
    {
        get { return _instance; }
    }

Hmm, tutto questo sembra un po 'complesso.

Perché è necessario un framework di iniezione delle dipendenze per ottenere un singleton? L'uso di un contenitore IOC va bene per alcune app aziendali (purché non sia abusato ovviamente), ma, ah, il tizio vuole solo sapere circa l'implementazione del modello.

Perché non creare sempre un'istanza con entusiasmo, quindi fornire un metodo che restituisca la statica, la maggior parte del codice sopra scritto scompare. Segui il vecchio adagio C2 - DoTheSimplestThingThatCouldPossiblyWork ...

Ti consiglio di leggere l'articolo Exploring the Singleton Design Pattern disponibile su MSDN. Descrive in dettaglio le caratteristiche del framework che semplificano l'implementazione del pattern.

A parte, darei un'occhiata alla lettura correlata su SO relativa ai Singleton .

Ignorando il problema di utilizzare o meno il modello Singleton, che è stato discusso altrove, implementerei un singleton come questo:

/// <summary>
/// Thread-safe singleton implementation
/// </summary>
public sealed class MySingleton {

    private static volatile MySingleton instance = null;
    private static object syncRoot = new object();

    /// <summary>
    /// The instance of the singleton
    /// safe for multithreading
    /// </summary>
    public static MySingleton Instance {
        get {
            // only create a new instance if one doesn't already exist.
            if (instance == null) {
                // use this lock to ensure that only one thread can access
                // this block of code at once.
                lock (syncRoot) {
                    if (instance == null) {
                        instance = new MySingleton();
                    }
                }
            }
            // return instance where it was just created or already existed.
            return instance;
        }
    }


    /// <summary>
    /// This constructor must be kept private
    /// only access the singleton through the static Instance property
    /// </summary>
    private MySingleton() {

    }

}

Il singleton statico è praticamente un modello anti se si desidera un design liberamente accoppiato. Se possibile, evitatelo e, a meno che non si tratti di un sistema molto semplice, consiglierei di dare un'occhiata a uno dei tanti framework di iniezione di dipendenza disponibili, come http://ninject.org/ o http://code.google.com / p / autofac / .

Per registrare / utilizzare un tipo configurato come singleton in autofac dovresti fare qualcosa del tipo:

var builder = new ContainerBuilder()
builder.Register(typeof(Dependency)).SingletonScoped()
builder.Register(c => new RequiresDependency(c.Resolve<Dependency>()))

var container = builder.Build();

var configured = container.Resolve<RequiresDependency>();

La risposta accettata è comunque una soluzione terribile, almeno controlla i ragazzi che hanno effettivamente implementato il modello.

public class Globals
{
    private string setting1;
    private string setting2;

    #region Singleton Pattern Implementation

    private class SingletonCreator
    {
        internal static readonly Globals uniqueInstance = new Globals();

        static SingletonCreator()
        {
        }
    }

    /// <summary>Private Constructor for Singleton Pattern Implementaion</summary>
    /// <remarks>can be used for initializing member variables</remarks>
    private Globals()
    {

    }

    /// <summary>Returns a reference to the unique instance of Globals class</summary>
    /// <remarks>used for getting a reference of Globals class</remarks>
    public static Globals GetInstance
    {
        get { return SingletonCreator.uniqueInstance; }
    }

    #endregion

    public string Setting1
    {
        get { return this.setting1; }
        set { this.setting1 = value; }
    }

    public string Setting2
    {
        get { return this.setting2; }
        set { this.setting2 = value; }
    }

    public static int Constant1 
    {
        get { reutrn 100; }
    }

    public static int Constat2
    {
        get { return 200; }
    }

    public static DateTime SqlMinDate
    {
        get { return new DateTime(1900, 1, 1, 0, 0, 0); }
    }

}

Mi piace questo modello, anche se non impedisce a qualcuno di creare un'istanza non singleton. A volte può essere meglio educare gli sviluppatori del tuo team sull'uso della giusta metodologia piuttosto che andare su lunghezze eroiche per impedire ad alcuni tirapiedi di usare il tuo codice nel modo sbagliato ...

    public class GenericSingleton<T> where T : new()
    {
        private static T ms_StaticInstance = new T();

        public T Build()
        {
            return ms_StaticInstance;
        }
    }

...
    GenericSingleton<SimpleType> builder1 = new GenericSingleton<SimpleType>();
    SimpleType simple = builder1.Build();

Questo ti darà una singola istanza (istanziato nel modo giusto) e sarà effettivamente pigro, perché il costruttore statico non viene chiamato fino a quando non viene chiamato Build ().

Quello che stai descrivendo sono semplicemente funzioni e costanti statiche, non un singleton. Il modello di progettazione singleton (che è molto raramente necessario) descrive una classe che è istanziata, ma solo una volta, automaticamente, al primo utilizzo.

Combina l'inizializzazione lenta con un segno di spunta per impedire l'istanza multipla. È davvero utile solo per le classi che racchiudono un concetto fisicamente singolare, come un wrapper attorno a un dispositivo hardware.

Le costanti e le funzioni statiche sono proprio questo: codice che non necessita affatto di un'istanza.

Chiediti questo: " Questa classe si interromperà se ce n'è più di un'istanza? " Se la risposta è no, non è necessario un singleton.

hmmm ... Poche costanti con funzioni correlate ... non sarebbe meglio raggiungere gli enum? So che puoi creare un enum personalizzato in Java con metodi e tutti, lo stesso dovrebbe essere raggiungibile in C #, se non supportato direttamente, puoi farlo con un semplice singleton di classe con costruttore privato.

Se le tue costanti sono semanticamente correlate dovresti considerare enum (o concetto equivalente) otterrai tutti i vantaggi delle variabili statiche const + sarai in grado di usare a tuo vantaggio il controllo del tipo del compilatore.

I miei 2 centesimi

Personalmente sceglierei un framework di iniezione delle dipendenze, come Unity, tutti sono in grado di configurare elementi singleton nel contenitore e migliorare l'accoppiamento passando da una dipendenza di classe a una dipendenza di interfaccia.

Nascondendo il costruttore pubblico, aggiungendo un campo statico privato per contenere questa sola istanza e aggiungendo un metodo factory statico (con inizializzatore pigro) per restituire quella singola istanza

public class MySingleton   
{  
    private static MySingleton sngltn; 
    private static object locker;  
    private MySingleton() {}   // Hides parameterless ctor, inhibits use of new()   
    public static MySingleton GetMySingleton()       
    {     
        lock(locker)
            return sngltn?? new MySingleton();
    }   
}

Ho scritto una lezione per il mio progetto usando il modello Singleton. È molto facile da usare Spero che funzionerà per te. Si prega di trovare il seguente codice.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace TEClaim.Models
{
public class LogedinUserDetails
{
    public string UserID { get; set; }
    public string UserRole { get; set; }
    public string UserSupervisor { get; set; }
    public LogedinUserDetails()
    {

    }

    public static LogedinUserDetails Singleton()
    {
        LogedinUserDetails oSingleton;

        if (null == System.Web.HttpContext.Current.Session["LogedinUserDetails"])
        {               
            oSingleton = new LogedinUserDetails();
            System.Web.HttpContext.Current.Session["LogedinUserDetails"] = oSingleton;
        }
        else
        {              
            oSingleton = (LogedinUserDetails)System.Web.HttpContext.Current.Session["LogedinUserDetails"];
        }

        //Return the single instance of this class that was stored in the session
        return oSingleton;
    }
}
}

Ora puoi impostare un valore variabile per il codice sopra nella tua applicazione in questo modo.

[HttpPost]
public ActionResult Login(FormCollection collection)
{
  LogedinUserDetails User_Details = LogedinUserDetails.Singleton();
  User_Details.UserID = "12";
  User_Details.UserRole = "SuperAdmin";
  User_Details.UserSupervisor = "815978";
  return RedirectToAction("Dashboard", "Home");
}

E puoi recuperare quei valori in questo modo ..

public ActionResult Dashboard()
    {
        LogedinUserDetails User_Details = LogedinUserDetails.Singleton();
        ViewData["UserID"] = User_Details.UserID;
        ViewData["UserRole"] = User_Details.UserRole;
        ViewData["UserSupervisor"] = User_Details.UserSupervisor;

        return View();
    }

In c # potrebbe essere (inizializzazione pigra e lazy):

public sealed class MySingleton
{
    static volatile Lazy<MySingleton> _instance = new Lazy<MySingleton>(() => new MySingleton(), true);
    public static MySingleton Instance => _instance.Value;
    private MySingleton() { }
}
public class Singleton
{
   private static Singleton _instance;
   public static Singleton Instance => _instance ?? (_instance = new Singleton());
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top