2008-10-29 7 views
24

Comment implémenter le modèle singleton en C#? Je veux y mettre mes constantes et certaines fonctions de base que j'utilise partout dans mon projet. Je veux les avoir 'Global' et ne pas avoir besoin de lier manuellement tous les objets que je crée.Comment implémenter un singleton en C#?

+1

Je pense que vous devrait prendre en compte les votes et reconsidérer votre réponse acceptée. –

+0

Je ne sais pas - la réponse de tvanfosson est géniale pour le corps de la question, même si ce n'est pas pour le titre. Peut-être changer le corps ou le titre pour correspondre les uns aux autres serait le meilleur :) –

+0

D'accord avec vous sur ce –

Répondre

28

Si vous stockez simplement des valeurs globales et avez des méthodes qui n'ont pas besoin d'état, vous n'avez pas besoin de singleton. Il suffit de rendre la classe et ses propriétés/méthodes statiques. Singleton est le plus utile lorsque vous avez une classe normale avec l'état, mais vous voulez seulement l'un d'entre eux. Les liens que d'autres ont fournis devraient être utiles pour explorer le modèle de Singleton.

+0

Si vous voulez uniquement héberger des constantes, utilisez le mot clé 'const'. Statique n'est pas requis. Gardez à l'esprit qu'en utilisant cette approche, les constantes deviennent directement insérées dans l'assemblage. – bryanbcook

+1

Impossible d'utiliser const si vous voulez avoir une méthode setter comme illustré. L'utilisation de const le rend en lecture seule. – tvanfosson

+0

Pour un global qui peut être lu et écrit par tout le monde .. Je recommande au moins un verrouillage minimum. – FOR

3

Je vous recommande de lire l'article Exploring the Singleton Design Pattern disponible sur MSDN. Il détaille les caractéristiques du cadre qui rendent le modèle simple à mettre en œuvre.

En passant, je voudrais vérifier le related reading on SO regarding Singletons.

+0

+1, bel article, quelle manière très simple d'implémenter le modèle singletton:

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

+0

URL plus récente pour le lien MSDN: http://msdn.microsoft.com/en-us/library/Ee817670%28pandp.10%29. aspx –

7

Singleton != Global. Vous semblez être à la recherche du mot-clé static.

4

singletons sens que si tant de ces conditions sont remplies:

  1. L'objet doit être globale
  2. Il ne doit jamais exister une unique instance de l'objet

Notez que # 2 ne signifie pas que vous comme l'objet pour avoir une seule instance - si c'est le cas, instancier simplement une seule fois - cela signifie que doit (comme dans, il est dangereux que cela ne soit pas vrai) ne soit qu'une seule instance.

Si vous voulez global, créez simplement une instance globale d'un objet (non signet) (ou rendez-le statique ou autre). Si vous voulez une seule instance, encore une fois, statique est votre ami. Aussi, instanciez simplement un seul objet.

C'est mon opinion quand même.

3

Ignorant la question de savoir si oui ou non vous devez utiliser le modèle Singleton, qui a été discuté ailleurs, je mettrait en œuvre un singleton comme ceci:

/// <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

Intéressant. Il serait utile de voir une brève description de votre utilisation de scellé, volatile et de verrouillage. – DOK

+1

C'est l'algorithme de verrouillage à double vérification. Vous devez faire très attention avec cela - un pied hors de propos (par exemple, ne pas rendre la variable d'instance volatile) et ce n'est pas sûr pour les threads. Les formes les plus simples font presque toujours ce qui est nécessaire, généralement plus efficacement IMO. –

+1

Voir mon simple singleton ci-dessus, Jon SKeet a raison. – FlySwat

3

singleton est à peu près un modèle contre si vous veulent un design faiblement couplé. Évitez si possible, et à moins que ce soit un système très simple, je vous recommande de jeter un oeil à l'un des nombreux cadres d'injection de dépendance disponibles, tels que http://ninject.org/ ou http://code.google.com/p/autofac/.

Pour vous inscrire/consommer un type configuré comme un singleton dans autofac vous feriez quelque chose comme ce qui suit:

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 réponse acceptée est une solution épouvantable en passant, au moins vérifier les chaps qui ont effectivement mis en œuvre le motif.

+0

La réponse acceptée n'est pas un singleton, mais exactement ce que je voulais atteindre. – Andre

4

Vous pouvez vraiment simplifier une implémentation singleton, ce que j'utilise:

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

    private static readonly FooService _instance = new FooService(); 

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

Pour en faire un vrai singleton, j'aurais mis le 'new' dans la propriété' Instance', à instancier une seule fois. – spoulson

+2

un fichier readonly statique privé a marqué BeforeFieldInit, il sera instancié une fois lorsque l'assembly est chargé, et ne le sera plus jamais. – FlySwat

1

Ce que vous décrivez est simplement des fonctions statiques et constantes, pas un singleton. Le motif de conception singleton (qui est très rarement nécessaire) décrit une classe instanciée, mais une seule fois, automatiquement, lors de la première utilisation.

Il combine une initialisation paresseuse avec une vérification pour éviter l'instanciation multiple. Ce n'est vraiment utile pour les classes qui enveloppent un concept qui est physiquement singulier, comme un wrapper autour d'un périphérique matériel.

Les constantes et fonctions statiques sont justes: un code qui n'a pas besoin d'instance du tout.

Posez-vous cette question: "Cette classe va-t-elle casser s'il y en a plus d'une instance?" Si la réponse est non, vous n'avez pas besoin d'un singleton.

1

hmmm ... Peu de constantes avec des fonctions connexes ... cela ne serait-il pas mieux d'enumerer? Je sais que vous pouvez créer une énumération personnalisée en Java avec des méthodes et tout, la même chose devrait être accessible en C#, si elle n'est pas directement supportée, elle peut être faite avec un simple singleton de classe avec un constructeur privé. Si vos constantes sont sémantiquement liées vous devriez considérer enums (ou concept équivalent) vous gagnerez tous les avantages des variables const statiques + vous pourrez utiliser à votre avantage le contrôle de type du compilateur.

Mon 2 cent

0

En cachant constructeur public, l'ajout d'un champ statique privé à tenir ce seul exemple, et l'ajout d'une méthode de fabrication statique (avec initialiseur paresseux) pour revenir que seule instance

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

Personnellement, je voudrais un framework d'injection de dépendance, comme Unity, tous sont capables de configurer des éléments singleton dans le conteneur et améliorerait le couplage en passant d'une dépendance de classe à une dépendance d'interface.

4

Hmm, tout cela semble un peu complexe. Pourquoi avez-vous besoin d'un framework d'injection de dépendance pour obtenir un singleton? L'utilisation d'un conteneur IOC convient à certaines applications d'entreprise (à condition qu'elles ne soient pas surexploitées bien sûr), mais, ah, le gars veut simplement savoir comment appliquer le modèle. Pourquoi ne pas toujours instancier avec empressement, puis fournir une méthode qui renvoie le statique, la plupart du code écrit ci-dessus puis disparaît. Suivez le vieil adage 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

J'aime ce modèle, même si elle ne l'empêche pas quelqu'un de créer une instance non-singleton. Il peut parfois peut être mieux d'éduquer les développeurs de votre équipe en utilisant la bonne méthode par rapport à des longueurs allant héroïques pour éviter une knucklehead d'utiliser votre code dans le mauvais sens ...

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

Cela vous donnera un instance unique (instanciée dans le bon sens) et sera effectivement paresseux, car le constructeur statique n'est pas appelé jusqu'à ce que Build() soit appelé.

0

J'ai écrit une classe pour mon projet en utilisant le motif Singleton. C'est très facile à utiliser. J'espère que cela fonctionnera pour vous. Veuillez trouver le code suivant.

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

valeur que vous pouvez maintenant définir la variable pour le code ci-dessus dans votre application comme celui-ci ..

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

Et vous pouvez récupérer les valeur comme ça ..

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