Pregunta

¿Cómo implemento el patrón de singleton en C #? Quiero poner en ella mis constantes y algunas funciones básicas, ya que las uso en todas partes en mi proyecto. Quiero tenerlos 'Global' y no necesito enlazarlos manualmente a cada objeto que creo.

¿Fue útil?

Solución

Si solo está almacenando algunos valores globales y tiene algunos métodos que no necesitan estado, no necesita singleton. Simplemente haga que la clase y sus propiedades / métodos sean estáticos.

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

   public static string MangleString( string someValue )
   {
   }
}

Singleton es más útil cuando tienes una clase normal con estado, pero solo quieres una de ellas. Los enlaces que otros han proporcionado deberían ser útiles para explorar el patrón de Singleton.

Otros consejos

Singleton! = Global . Parece que estás buscando la palabra clave static .

Los Singletons solo tienen sentido si ambas de estas condiciones son verdaderas:

  1. El objeto debe ser global
  2. Solo debe existir una instancia única del objeto

Tenga en cuenta que el # 2 no significa que le gustaría gustar que el objeto tenga una sola instancia; si ese es el caso, simplemente cree una instancia una sola vez, esto significa que debe (como en, es peligroso que esto no sea verdad) solo puede ser una sola instancia.

Si desea global, solo cree una instancia global de algún objeto (no signleton) (o hágalo estático o lo que sea). Si solo quieres una instancia, estática es tu amigo. Además, simplemente cree una instancia de un solo objeto.

Esa es mi opinión de todos modos.

Realmente puedes simplificar una implementación de singleton, esto es lo que uso:

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

    private static readonly FooService _instance = new FooService();

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

Hmm, todo esto parece un poco complejo.

¿Por qué necesita un marco de inyección de dependencias para obtener un singleton? El uso de un contenedor IOC está bien para algunas aplicaciones empresariales (siempre que no se use en exceso, por supuesto), pero, ah, el tipo solo quiere saber más sobre la implementación del patrón.

¿Por qué no siempre se crea instantes con entusiasmo? Luego, proporcione un método que devuelva la estática, la mayoría del código escrito anteriormente desaparece. Siga el viejo adagio de C2: DoTheSimplestThingThatCouldPossiblyWork ...

Le recomendaría que lea el artículo Explorando el patrón de diseño de Singleton disponible en MSDN. Detalla las características del marco que hacen que el patrón sea fácil de implementar.

Como nota aparte, revisé la lectura relacionada en SO sobre Singletons .

Ignorando el tema de si debe o no usar el patrón Singleton, que se ha discutido en otra parte, implementaría un singleton como este:

/// <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() {

    }

}

El singleton estático es casi un patrón anti si desea un diseño acoplado de forma flexible. Evite si es posible y, a menos que este sea un sistema muy simple, recomendaría echar un vistazo a uno de los muchos marcos de inyección de dependencias disponibles, como http://ninject.org/ o http://code.google.com / p / autofac / .

Para registrar / consumir un tipo configurado como singleton en autofac, haría algo como lo siguiente:

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 respuesta aceptada es una solución terrible, por cierto, al menos verifique los capítulos que implementaron el patrón.

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

}

Me gusta este patrón, aunque no impide que alguien cree una instancia que no sea singleton. A veces, puede ser mejor educar a los desarrolladores de su equipo sobre el uso de la metodología correcta en lugar de ir a lo heroico para evitar que algunos nudillos usen su código de manera incorrecta ...

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

Esto te dará una sola instancia (se ejemplificará de la manera correcta) y será perezoso, ya que no se llama al constructor estático hasta que se llama a Build ().

Lo que estás describiendo son simplemente funciones y constantes estáticas, no un singleton. El patrón de diseño de singleton (que rara vez se necesita) describe una clase que está instanciada, pero solo una vez, automáticamente, cuando se usa por primera vez.

Combina la inicialización perezosa con una verificación para evitar la creación de instancias múltiples. Solo es realmente útil para las clases que envuelven algún concepto que es físicamente singular, como un envoltorio alrededor de un dispositivo de hardware.

Las constantes y funciones estáticas son solo eso: código que no necesita una instancia en absoluto.

Pregúntate esto: " ¿Se romperá esta clase si hay más de una instancia de eso? " Si la respuesta es no, no necesitas un singleton.

hmmm ... Pocas constantes con funciones relacionadas ... ¿eso no se lograría mejor a través de enumeraciones? Sé que puede crear una enumeración personalizada en Java con métodos y todo, lo mismo debería ser alcanzable en C #, si no se admite directamente, entonces puede hacerse con singleton de clase simple con constructor privado.

Si sus constantes están relacionadas semánticamente, debe considerar las enumeraciones (o concepto equivalente) y obtendrá todas las ventajas de las variables estáticas constantes + podrá utilizar para su ventaja la verificación de tipos del compilador.

Mi 2 centavo

Personalmente apostaría por un marco de inyección de dependencias, como Unity, todos ellos pueden configurar elementos singleton en el contenedor y mejorarían el acoplamiento al pasar de una dependencia de clase a una dependencia de interfaz.

Ocultando al constructor público, agregando un campo estático privado para contener esta única instancia, y agregando un método de fábrica estático (con inicializador lento) para devolver esa instancia única

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

He escrito una clase para mi proyecto usando el patrón Singleton. Es muy fácil de usar. Espero que funcione para usted. Por favor encuentre el código siguiente.

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;
    }
}
}

Ahora puede establecer un valor variable para el código anterior en su aplicación de esta manera ...

[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");
}

Y puedes recuperar esos valores como este ...

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

En c # podría ser (Thread safe así como inicialización lenta):

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());
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top