30 votes

Quel est le bon modèle de template générique threadsafe singleton en C# ?

J'ai le modèle singleton C# suivant, y a-t-il un moyen de l'améliorer ?

    public class Singleton<T> where T : class, new()
    {

        private static object _syncobj = new object();
        private static volatile T _instance = null;
        public static T Instance
        {
            get
            {
                if (_instance == null)
                {
                    lock (_syncobj)
                    {
                        if (_instance == null)
                        {
                            _instance = new T();
                        }
                    }
                }
                return _instance;
            }
        }

        public Singleton()
        { }

    }

Exemple d'utilisation préférée :

class Foo : Singleton<Foo> 
{
} 

Related :

Une implémentation évidente du singleton pour .NET ?

0 votes

En l'état actuel des choses, j'ai dû ajouter "protected" au constructeur pour pouvoir compiler.

0 votes

La question est difficile à lire. Est-ce que "Cette classe Singleton générique est bonne ? Est-ce qu'elle est thread safe ?" donne-t-il toujours le bon sens ?

0 votes

N'hésitez pas à faire ce que vous voulez de cette question, c'est un wiki communautaire.

18voto

Jon Limjap Points 46429

Selon Jon Skeet dans Implémentation du modèle Singleton en C# le code que vous avez posté est en fait considéré comme un mauvais code, car il semble cassé lorsqu'il est vérifié par rapport à la norme ECMA CLI.

Attention également : chaque fois que vous instanciez votre objet avec un nouveau type de T, il devient une autre instance ; cela ne se reflète pas dans votre singleton original.

0 votes

C'est un bon message ... J'ai modifié la question pour tenir compte de ces changements

10voto

Ilya Ryzhenkov Points 5731

Ce code ne compilera pas, vous avez besoin de la contrainte "class" sur T.

De plus, ce code nécessite un constructeur public sur la classe cible, ce qui n'est pas bon pour un singleton, car vous ne pouvez pas contrôler au moment de la compilation que vous obtenez une instance (unique) uniquement via la propriété (ou le champ) Instance. Si vous n'avez pas d'autres membres statiques que la propriété Instance, vous pouvez vous contenter de ce code :

class Foo
{
  public static readonly Instance = new Foo();
  private Foo() {}
  static Foo() {}
}

Il est thread safe (garanti par le CLR) et lazy (l'instance est créée au premier accès au type). Pour en savoir plus sur BeforeFieldInit et sur la raison pour laquelle nous avons besoin d'un constructeur statique ici, voir https://csharpindepth.com/articles/BeforeFieldInit .

Si vous souhaitez avoir d'autres membres statiques publics sur le type, mais créer un objet uniquement lors de l'accès à l'instance, vous pouvez créer un type imbriqué, comme dans le cas suivant https://csharpindepth.com/articles/Singleton

1 votes

Vous avez la bonne réponse. C'est la meilleure implémentation parce que c'est la plus simple, elle est intégrée au langage et vous ne brûlez pas votre classe de base pour implémenter une fonctionnalité triviale.

0 votes

@wizlb En déplaçant la logique commune vers la classe de base, vous prenez la responsabilité de vous assurer que le modèle est utilisé correctement par les auteurs des classes dérivées vers la classe de base unique.

8voto

Darksider Points 2692

Avec l'aimable autorisation de Judith Bishop, http://patterns.cs.up.ac.za/

Cette mise en œuvre du modèle singleton assure une initialisation paresseuse.

//  Singleton PatternJudith Bishop Nov 2007
//  Generic version

public class Singleton<T> where T : class, new()
{
    Singleton() { }

    class SingletonCreator
    {
        static SingletonCreator() { }
        // Private object instantiated with private constructor
        internal static readonly T instance = new T();
    }

    public static T UniqueInstance
    {
        get { return SingletonCreator.instance; }
    }
}

3 votes

Je suis désolé, je ne suis plus sûr que ce soit correct, le problème est que vous vous retrouvez avec un type qui est à la fois nouveau et accessible via le singleton ...

0 votes

Juste une petite question Sam : Comment avez-vous réussi à créer une nouvelle instance de la classe ? Selon le code ci-dessus, le constructeur est privé...

1 votes

Ce pattern est bon, mais il y a une chose qui me dérange : la contrainte de type new() implique que le singleton a un constructeur public, ce qui brise le pattern singleton. Je pense que cette contrainte devrait être supprimée, et que Activator.CreateInstance devrait être utilisé pour appeler le constructeur protégé.

5voto

Alexandr Points 566

C'est ce que je constate en utilisant .NET 4

public class Singleton<T> where T : class, new()
    {
        Singleton (){}

        private static readonly Lazy<T> instance = new Lazy<T>(()=> new T());

        public static T Instance { get { return instance.Value; } } 
    }

1 votes

La classe n'est pas un singleton, car le constructeur public permet de créer plusieurs instances . La classe est utile, mais je l'ai renommée en SingleInstanceBase.

0 votes

Veuillez consulter la question. C'est la façon d'améliorer la classe de question en utilisant .net 4

3voto

Binoj Antony Points 7519

Plus de détails sur cette réponse sur un autre fil : Comment implémenter un singleton en C# ?

Cependant, le fil n'utilise pas Générique .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X