2008-10-29 9 views
24

¿Cómo implemento el patrón singleton en C#? Quiero poner mis constantes y algunas funciones básicas en él, ya que las utilizo en todas partes de mi proyecto. Quiero que sean 'globales' y no es necesario vincularlos manualmente a cada objeto que creo.¿Cómo implementar un singleton en C#?

+1

Creo que se debe tener en cuenta los votos y reconsiderar su respuesta aceptada. –

+0

No lo sé - la respuesta de tvanfosson es genial para el cuerpo de la pregunta, incluso si no es por el título. Podría decirse que cambiar el cuerpo o el título para que coincidan entre sí sería lo mejor :) –

+0

De acuerdo con usted en que –

Respuesta

28

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

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

    public static string MangleString(string someValue) 
    { 
    } 
} 

Singleton es más útil cuando se tiene una clase normal con el estado, pero sólo desea uno de ellos. Los enlaces que otros han proporcionado deberían ser útiles para explorar el patrón de Singleton.

+0

Si solo quiere albergar constantes, use la palabra clave 'const'. Static no es requerido. Tenga en cuenta que al usar este enfoque, las constantes se incrustan directamente en el conjunto. – bryanbcook

+1

No se puede usar const si desea tener un método setter como se ilustra. Usar const lo hace de solo lectura. – tvanfosson

+0

Para un mundo que todos puedan leer y escribir ... Recomiendo al menos un candado mínimo. – FOR

3

Le recomendaría que lea el artículo Exploring the Singleton Design Pattern disponible en MSDN. Detalla las características del marco que hacen que el patrón sea simple de implementar.

Como un aparte, echaría un vistazo al related reading on SO regarding Singletons.

+0

+1, buen artículo, qué manera más sencilla de implementar el patrón singletton:

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

+0

URL más reciente para el enlace MSDN: http://msdn.microsoft.com/en-us/library/Ee817670%28pandp.10%29. aspx –

7

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

4

Singleton sólo tienen sentido si tanto de estas condiciones son verdaderas:

  1. el objeto debe ser mundial
  2. Tiene que solamente alguna vez llega a sola instancia del objeto

Tenga en cuenta que # 2 no significa que usted como el objeto para que solo tenga una sola instancia, si es así, simplemente ejemplifíquelo solo una vez, significa que debe (es decir, es peligroso que esto no sea cierto), solo que sea una sola instancia.

Si desea global, solo haga una instancia global de algún objeto (no como un esqueleto) (o hágalo estático o lo que sea). Si solo quieres una instancia, una vez más, static es tu amigo. Además, simplemente crea una instancia de un solo objeto.

Esa es mi opinión de todos modos.

3

Haciendo caso omiso de la cuestión de si debe o no a utilizar el patrón Singleton, que se ha discutido en otra parte, me gustaría poner en práctica un conjunto unitario de esta manera:

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

    } 

} 
+0

Interesante. Sería útil ver una breve descripción del uso de sellado, volátil y seguro. – DOK

+1

Es el algoritmo de bloqueo comprobado. Debe tener mucho cuidado con esto: un pie fuera de lugar (por ejemplo, no hacer que la variable de instancia sea volátil) y no es seguro para subprocesos. Las formas más simples casi siempre hacen lo que se requiere, generalmente de manera más eficiente. –

+1

Ver mi singleton simple arriba, Jon SKeet tiene razón. – FlySwat

3

singleton estático es más o menos un patrón contra si quiero un diseño ligeramente acoplado. Evitar si es posible, y a menos que este sea un sistema muy simple, recomendaría echarle un vistazo a uno de los muchos marcos de inyección de dependencia disponibles, como http://ninject.org/ o http://code.google.com/p/autofac/.

Para registrar/consumen un tipo configurado como un conjunto unitario en autofac que 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 horrible por cierto, al menos comprobar los tipos que realmente implementadas el patrón.

+0

La respuesta aceptada no es solo, sino exactamente lo que quería lograr. – Andre

4

Realmente se puede simplificar una aplicación Singleton, esto es lo que yo uso:

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

    private static readonly FooService _instance = new FooService(); 

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

Para que sea un singleton verdadero, habría puesto el 'nuevo' en la propiedad' Instance', para instanciar solo una vez. – spoulson

+2

un archivo estático privado de solo lectura tiene marcado BeforeFieldInit, creará una instancia una vez que se cargue el ensamblado, y nunca volverá a hacerlo. – FlySwat

1

Lo que usted describe es meramente funciones estáticas y constantes, no un conjunto unitario. El patrón de diseño singleton (que muy raramente se necesita) describe una clase que es instanciada, pero solo una vez, automáticamente, cuando se utiliza por primera vez.

Combina la inicialización diferida con una comprobació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 a ti mismo: "¿Se romperá esta clase si hay más de una instancia de la misma?" Si la respuesta es no, no necesita un singleton.

1

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

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

Mi 2 céntimos

0

Al ocultar constructor público, añadiendo un campo estático privada para contener este único caso, y la adición de un método de fábrica estática (con inicializador perezoso) para devolver esa única instancia

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

Personalmente, optaría por un marco de inyección de dependencias, como Unity, todos ellos pueden configurar elementos únicos en el contenedor y mejorarían el acoplamiento pasando de una dependencia de clase a una dependencia de interfaz.

4

Hmm, todo esto parece un poco complejo.

¿Por qué necesita un marco de inyección de dependencia para obtener un singleton? Usar un contenedor IOC está bien para una aplicación empresarial, (siempre y cuando no se use en exceso, por supuesto), pero, ah, el chico solo quiere saber de cerca la implementación del patrón.

¿Por qué no siempre crear una instancia entusiasta, luego proporcionar un método que devuelve la estática, la mayoría del código escrito arriba luego desaparece. Siga el viejo dicho C2 - DoTheSimplestThingThatCouldPossiblyWork ...

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

} 
2

me gusta este patrón, aunque no impide que alguien cree una instancia no Singleton. A veces puede puede ser mejor para educar a los desarrolladores en su equipo sobre el uso de la metodología de la derecha frente a ir a longitudes heroicas para prevenir algunas knucklehead la utilización de su código por el camino equivocado ...

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 le dará una instancia única (instanciado de la manera correcta) y será efectivamente vago, porque el constructor estático no se llama hasta que se llame a Build().

0

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

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 se puede establecer el valor variable para el código anterior en su aplicación como esta ..

[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 puede recuperar dichos valores como esto ..

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