Qu'est-ce qu'un singleton en C #?


182

Qu'est-ce qu'un Singleton et quand dois-je l'utiliser?



4
En outre, le Singleton est l'un des modèles de conception les plus largement utilisés et les plus abusés dans la programmation OO.
ChaosPandion

3
@Fabiano: Parce qu'il a une façon de créer des couplages qui n'ont aucun sens (comment puis-je Xparler Y? Faites juste Yun singleton!), Ce qui conduit à son tour à des difficultés de test / débogage et à un style procédural de programmation. Parfois, des singletons sont nécessaires; la plupart du temps, non.
Aaronaught le

3
C'est l'une de mes questions d'entrevue téléphonique standard. La bonne réponse est: jamais.
jonnii

3
@jonnii c'est bien, ça aide à avertir les futurs développeurs à quoi ressemble leur patron!
M. Boy

Réponses:


145

Un singleton est une classe qui ne permet de créer qu'une seule instance d'elle-même - et donne un accès simple et facile à ladite instance. La prémisse singleton est un modèle à travers le développement logiciel.

Il existe une implémentation C # "Implémentation du modèle Singleton en C #" couvrant la plupart de ce que vous devez savoir - y compris quelques bons conseils concernant la sécurité des threads .

Pour être honnête, il est très rare que vous ayez besoin d'implémenter un singleton - à mon avis, cela devrait être l'une de ces choses dont vous devriez être conscient, même s'il n'est pas utilisé trop souvent.


2
beau tutoriel mais merde sacrée qu'est-ce qu'ils ont fait à l'indentation du code
Inspi

Voici un lien plus direct vers ce que je considère comme l'implémentation idéale en 2020. C'est-à-dire «en utilisant le type Lazy <T> de .NET 4 », ainsi que le lien vers le Microsoft Doc pour le Lazy<T> Class.
Chiramisu le

52

Vous avez demandé C #. Exemple trivial:


public class Singleton
{
    private Singleton()
    {
        // Prevent outside instantiation
    }

    private static readonly Singleton _singleton = new Singleton();

    public static Singleton GetSingleton()
    {
        return _singleton;
    }
}

14
pas thread safe.two thread peut appeler en même temps et peut créer deux objets séparés.
Alagesan Palani

5
@Alagesan Palani, en effet vous avez raison. Je ne suis pas compétent dans les détails de bas niveau de l'initialisation au niveau de la classe, mais je pense que la modification que j'ai apportée répond au problème de la sécurité des threads.
Chris Simmons

3
bien sûr, je ne montre pas que vous vous trompez. Je donne un indice au lecteur sur la sécurité des threads, afin qu'ils fassent attention s'ils doivent y faire face.
Alagesan Palani

9
Non, je pense que votre commentaire est important. Étant donné qu'un singleton est censé fournir une - et une seule - instance, la condition de concurrence ici ouvre la possibilité que plusieurs soient livrés. Voir la version maintenant, avec l'initialisation du champ statique. Je crois que cela résout le problème de la sécurité des threads, si je lis correctement la documentation et cette réponse SO .
Chris Simmons

1
@AlagesanPalani, je vois que vous avez déclaré que plusieurs autres réponses ne sont pas thread-safe. Souhaitez-vous fournir une solution thread-safe?
Bonez024

39

Description: Une classe pour laquelle il n'existe qu'une seule instance persistante pendant toute la durée de vie d'une application. Voir Modèle Singleton .

Quand faut-il l'utiliser: le moins possible. Seulement lorsque vous êtes absolument certain d'en avoir besoin. Je suis réticent à dire «jamais», mais il existe généralement une meilleure alternative, comme l'injection de dépendances ou simplement une classe statique.


16
Je ne suis pas sûr qu'une classe statique soit une meilleure alternative qu'un singleton ... cela dépend vraiment de la situation et de la langue.
marcgg

5
Les classes statiques ne se comportent pas de la même manière qu'un singleton, un singleton peut être passé dans des méthodes en tant que paramètre alors qu'une classe statique ne le peut pas.
TabbyCool

4
D'accord avec marcgg - Je ne vois pas une classe statique comme une bonne alternative aux singletons, car vous avez toujours le problème de fournir un substitut, par exemple lors du test d'un composant qui dépend de cette classe. Mais je vois aussi différentes utilisations, une classe statique serait généralement utilisée pour des fonctions utilitaires indépendantes qui sont indépendantes de l'état, où un singleton est une instance de classe réelle, et il stockerait généralement un état. J'accepte complètement d'utiliser DI à la place, puis je dis à votre conteneur DI que vous souhaitez qu'il n'utilise qu'une seule instance de cette classe.
Pete

9
J'ai décliné cette réponse car elle ne me donne aucune information sur le moment de l'utiliser. "Seulement quand vous en avez besoin" ne me donne pas vraiment d'informations pour quelqu'un qui est nouveau dans les singletons.
Sergio Tapia

9
@Adkins: DI signifie Dependency Injection, c'est-à-dire lorsqu'une dépendance de classe est transmise via (généralement) un constructeur ou une propriété publique. La DI seule ne résout pas le problème de la «distance», mais elle est généralement implémentée avec un conteneur d'inversion de contrôle (IoC) qui sait comment initialiser automatiquement toutes les dépendances. Donc, si vous créez un Singleton pour résoudre le problème «X ne sait pas comment trouver / parler à Y», une combinaison de DI et d'IoC peut résoudre le même problème avec un couplage plus lâche.
Aaronaught le

27

une autre façon d'implémenter singleton en c #, je préfère personnellement cette façon car vous pouvez accéder à l'instance de la classe singeton en tant que propriété au lieu d'une méthode.

public class Singleton
    {
        private static Singleton instance;

        private Singleton() { }

        public static Singleton Instance
        {
            get
            {
                if (instance == null)
                    instance = new Singleton();
                return instance;
            }
        }

        //instance methods
    }

mais bon, pour autant que je sache, les deux méthodes sont considérées comme «bonnes», donc c'est juste une question de saveur personnelle.


11
pas thread safe.two thread peut appeler en même temps et peut créer deux objets séparés.
Alagesan Palani

11
using System;
using System.Collections.Generic;
class MainApp
{
    static void Main()
    {
        LoadBalancer oldbalancer = null;
        for (int i = 0; i < 15; i++)
        {
            LoadBalancer balancerNew = LoadBalancer.GetLoadBalancer();

            if (oldbalancer == balancerNew && oldbalancer != null)
            {
                Console.WriteLine("{0} SameInstance {1}", oldbalancer.Server, balancerNew.Server);
            }
            oldbalancer = balancerNew;
        }
        Console.ReadKey();
    }
}

class LoadBalancer
{
    private static LoadBalancer _instance;
    private List<string> _servers = new List<string>();
    private Random _random = new Random();

    private static object syncLock = new object();

    private LoadBalancer()
    {
        _servers.Add("ServerI");
        _servers.Add("ServerII");
        _servers.Add("ServerIII");
        _servers.Add("ServerIV");
        _servers.Add("ServerV");
    }

    public static LoadBalancer GetLoadBalancer()
    {
        if (_instance == null)
        {
            lock (syncLock)
            {
                if (_instance == null)
                {
                    _instance = new LoadBalancer();
                }
            }
        }

        return _instance;
    }

    public string Server
    {
        get
        {
            int r = _random.Next(_servers.Count);
            return _servers[r].ToString();
        }
    }
}

J'ai pris le code de dofactory.com , rien de si sophistiqué mais je trouve cela bien bon que des exemples avec Foo and Bar, ainsi qu'un livre de Judith Bishop sur C # 3.0 Design Patterns a un exemple d'application active dans Mac Dock.

Si vous regardez le code, nous construisons en fait de nouveaux objets sur la boucle for , ce qui crée un nouvel objet mais réutilise l'instance, ce qui fait que l'ancien équilibreur et le nouvel équilibreur ont la même instance, comment? son dû au mot-clé statique utilisé sur la fonction GetLoadBalancer () , malgré la valeur de serveur différente qui est une liste aléatoire, statique sur GetLoadBalancer () appartient au type lui-même plutôt qu'à un objet spécifique.

De plus, il y a un double verrouillage de contrôle ici

if (_instance == null)
            {
                lock (syncLock)
                {
                    if (_instance == null)

depuis MSDN

Le mot clé lock garantit qu'un thread n'entre pas dans une section critique du code alors qu'un autre thread se trouve dans la section critique. Si un autre thread essaie de saisir un code verrouillé, il attendra, se bloque, jusqu'à ce que l'objet soit libéré.

donc à chaque fois qu'un verrou d'exclusion mutuelle est émis, même s'il n'est pas nécessaire, ce qui est inutile, nous avons donc une vérification nulle.

Espérons que cela aide à dégager davantage.

Et s'il vous plaît commentez si je comprends bien.


6

Un singleton (et cela n'est pas lié à C #, c'est un modèle de conception OO) est lorsque vous souhaitez autoriser la création d'une seule instance d'une classe dans votre application. Les utilisations incluraient généralement des ressources mondiales, bien que je dirai d'après mon expérience personnelle, elles sont très souvent la source de grandes douleurs.


5

Alors qu'il ne peut y avoir qu'une seule instance d'un singleton, ce n'est pas la même chose qu'une classe statique. Une classe statique ne peut contenir que des méthodes statiques et ne peut jamais être instanciée, alors que l'instance d'un singleton peut être utilisée de la même manière que tout autre objet.


2

C'est un modèle de conception et il n'est pas spécifique à c #. Plus d'informations à ce sujet sur Internet et SO, comme sur cet article de wikipedia .

En génie logiciel, le modèle singleton est un modèle de conception utilisé pour restreindre l'instanciation d'une classe à un objet. Ceci est utile lorsqu'un seul objet est nécessaire pour coordonner les actions dans le système. Le concept est parfois généralisé aux systèmes qui fonctionnent plus efficacement lorsqu'un seul objet existe, ou qui restreignent l'instanciation à un certain nombre d'objets (par exemple cinq). Certains le considèrent comme un anti-pattern, jugeant qu'il est surutilisé, introduit des limitations inutiles dans les situations où une seule instance d'une classe n'est pas réellement requise, et introduit un état global dans une application.

Vous devriez l'utiliser si vous voulez une classe qui ne peut être instanciée qu'une seule fois.


2

Je l'utilise pour les données de recherche. Charger une fois à partir de la base de données.

public sealed class APILookup
    {
        private static readonly APILookup _instance = new APILookup();
        private Dictionary<string, int> _lookup;

        private APILookup()
        {
            try
            {
                _lookup = Utility.GetLookup();
            }
            catch { }
        }

        static APILookup()
        {            
        }

        public static APILookup Instance
        {
            get
            {
                return _instance;
            }
        }
        public Dictionary<string, int> GetLookup()
        {
            return _lookup;
        }

    }

2

Qu'est-ce qu'un singleton:
C'est une classe qui permet de créer une seule instance d'elle-même, et donne généralement un accès simple à cette instance.

Quand devriez-vous utiliser:
cela dépend de la situation.

Remarque: veuillez ne pas utiliser sur une connexion db, pour une réponse détaillée, veuillez vous référer à la réponse de @Chad Grant

Voici un exemple simple de Singleton:

public sealed class Singleton
{
    private static readonly Singleton instance = new Singleton();

    // Explicit static constructor to tell C# compiler
    // not to mark type as beforefieldinit
    static Singleton()
    {
    }

    private Singleton()
    {
    }

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

Vous pouvez également utiliser Lazy<T>pour créer votre fichier Singleton.

Voir ici pour un exemple plus détaillé utilisantLazy<T>


1

Voici ce qu'est singleton: http://en.wikipedia.org/wiki/Singleton_pattern

Je ne connais pas C #, mais c'est en fait la même chose dans tous les langages, seule l'implémentation diffère.

Vous devriez généralement éviter le singleton lorsque c'est possible, mais dans certaines situations, c'est très pratique.

Désolé pour mon anglais ;)


votre anglais est OK :)
FrenkyB

1

La classe Singleton est utilisée pour créer une seule instance pour l'ensemble du domaine d'application.

public class Singleton
{
    private static Singleton singletonInstance = CreateSingleton();

    private Singleton()
    {
    }

    private static Singleton CreateSingleton()
    {
        if (singletonInstance == null)
        {
            singletonInstance = new Singleton();
        }

        return singletonInstance;
    }

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

Dans cet article, il est décrit comment nous pouvons créer une classe singleton thread-safe à l'aide de la variable readonly et leur utilisation pratique dans les applications.


1

Je sais qu'il est très tard pour répondre à la question, mais avec Auto-Property, vous pouvez faire quelque chose comme ça:

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

Singletonest votre classe et peut être via, dans ce cas, la propriété readonly Instance.


0

EX Vous pouvez utiliser Singleton pour les informations globales qui doivent être injectées.

Dans mon cas, je conservais les détails de l'utilisateur connecté (nom d'utilisateur, autorisations, etc.) dans Global Static Class. Et quand j'ai essayé d'implémenter le test unitaire, je ne pouvais pas injecter de dépendance dans les classes Controller. Ainsi, j'ai changé ma classe statique en modèle Singleton.

public class SysManager
{
    private static readonly SysManager_instance = new SysManager();

    static SysManager() {}

    private SysManager(){}

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

http://csharpindepth.com/Articles/General/Singleton.aspx#cctor


0

Nous devons utiliser le Singleton Design Pattern en C # lorsque nous devons nous assurer qu'une seule instance d'une classe particulière va être créée, puis fournir un accès global simple à cette instance pour l'ensemble de l'application.

Scénarios en temps réel dans lesquels vous pouvez utiliser le modèle de conception Singleton: Proxies de service: comme nous le savons, l'appel d'une API de service est une opération étendue dans une application. Le processus qui prend la plupart du temps est de créer le client de service afin d'appeler l'API de service. Si vous créez le proxy de service en tant que Singleton, les performances de votre application seront améliorées.

Façades: Vous pouvez également créer les connexions à la base de données en tant que Singleton, ce qui peut améliorer les performances de l'application.

Journaux: dans une application, l'exécution de l'opération d'E / S sur un fichier est une opération coûteuse. Si vous créez votre Logger en tant que Singleton, cela améliorera les performances de l'opération d'E / S.

Partage de données: si vous avez des valeurs constantes ou des valeurs de configuration, vous pouvez conserver ces valeurs dans Singleton afin qu'elles puissent être lues par d'autres composants de l'application.

Mise en cache: comme nous le savons, récupérer les données d'une base de données est un processus qui prend du temps. Dans votre application, vous pouvez mettre en cache le maître et la configuration en mémoire ce qui évitera les appels DB. Dans de telles situations, la classe Singleton peut être utilisée pour gérer la mise en cache avec la synchronisation des threads d'une manière efficace, ce qui améliore considérablement les performances de l'application.

Inconvénients du modèle de conception Singleton en C # Les inconvénients de l'utilisation du modèle de conception Singleton en C # sont les suivants:

Les tests unitaires sont très difficiles car ils introduisent un état global dans une application. Cela réduit le potentiel de parallélisme dans un programme car pour accéder à l'instance singleton dans un environnement multi-thread, vous devez sérialiser l'objet à l'aide du verrouillage.

J'ai pris cela de l'article suivant.

https://dotnettutorials.net/lesson/singleton-design-pattern/


0

Thread Safe Singleton sans utiliser de verrous et sans instanciation paresseuse.

Cette implémentation a un constructeur statique, elle ne s'exécute donc qu'une seule fois par domaine d'application.

public sealed class Singleton
{

    static Singleton(){}

    private Singleton(){}

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

}
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.