2011-06-08 2 views
1

Je faisais des recherches sur le modèle singleton pour C# J'ai trouvé cet exemple sur le site msdn.motif singleton en C# Question

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

    private Singleton(){} 

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

Parce que l'instance Singleton est référencé par un membre statique variable privée , l'instanciation n'a pas se produit jusqu'à ce que la classe est d'abord référencé par un appel à la propriété instance . Cette solution par conséquent implémente une forme de la propriété d'instanciation paresseuse , comme dans la forme de motifs de conception de Singleton.

Je ne suis pas assez sûr quand la mémoire allouée à se

private static readonly Singleton instance 

1) Est-il se produire lorsque la propriété est appelée instance ou avant même?

2) J'ai besoin de forcer la classe à créer une nouvelle mémoire parfois pour purger son contenu. Est-il sécuritaire de le faire en utilisant set?

set 
{ 
instance = null; 
} 
+3

* forme de l'instanciation paresseux * dit tout – V4Vendetta

+1

Où est-ce que (très mal) 'set {}' viennent? –

+1

Votre deuxième question est tellement logique. – CodesInChaos

Répondre

6

Dans l'exemple de code fourni, l'instance singleton sera créée au moment du premier accès à la classe. Cela signifie pour votre exemple au moment où Instance est appelé pour la première fois.

un aperçu plus concret que vous trouverez dans l'article de Jon Skeet Implementing the Singleton Pattern in C#, voir méthode 4.

En gros, afin d'obtenir un comportement vraiment paresseux quelque chose comme

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

    static Singleton(){} 
    private Singleton(){} 

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

est suffisant.

(Mais de toute façon, la pleine et bien meilleure vue d'ensemble se trouve dans l'article mentionné.)

EDIT
En fait, comme il ressort de l'article mentionné, l'instance n'est pas garanti à créer au premier accès, à cause de la marque BeforeFiledInit. Vous devez ajouter un constructeur statique vide, de cette façon il est garanti d'être paresseux. Sinon, l'instance sera créée à un moment indéterminé entre le démarrage du programme et le premier accès. (Runtime .NET 2.0 est connu pour avoir une stratégie plus avide, de sorte que vous obtiendrez probablement pas le comportement paresseux.)

Je cite ledit article:

La paresse est de type initializers ne peut être garanti par .NET lorsque le type n'est pas marqué avec un drapeau spécial appelé beforefieldinit. Malheureusement, le compilateur C# marque [...] tous les types qui n'ont pas de constructeur statique comme beforefieldinit.

EDIT 2
Si vous voulez que l'objet singleton pour nettoyer, vous devez inclure cette fonctionnalité dans la classe Singleton elle-même.

La suppression de la valeur de la propriété fera en sorte que votre classe ne sera plus un singleton! Imaginez que quelqu'un accède au singleton et obtient l'instance singleton. Après cela, vous définissez la propriété à null. L'objet existant de la classe Singleton ne disparaîtra pas, car il y a toujours une référence! Ainsi, la prochaine fois que vous accéderez à la propriété Instance, une autre instance de la classe Singleton sera créée. Donc vous avez perdu deux choses: votre objet n'est plus un singleton (parce que vous avez deux instances existantes en même temps), et la mémoire n'a pas été effacée non plus.

0

Il est dit dans la citation que vous avez posté:

l'instanciation ne se produit pas jusqu'à ce que la classe est d'abord référencé par un appel à la propriété de l'instance

Alors ... Chaque fois que vous appelez .Instance, ou à un moment donné avant.

+0

Le problème est que cette citation n'est pas garantie par la spécification. Ce qui conduit à la partie "ou à un moment avant". – CodesInChaos

0

Les membres statiques sont initialisés avant que le membre statique soit accédé pour la première fois et avant le constructeur statique, le cas échéant.

Read more on MSDN

3

La spécification C# dit:

10.5.5.1 initialisation champ statique

champ statique initializers variables d'une classe correspond à une séquence de tâches qui sont exécutées dans le texte dans lequel ils apparaissent dans la déclaration de classe. Si un constructeur statique (§10.12) existe dans la classe, l'exécution des initialiseurs de champs statiques se produit immédiatement avant l'exécution de ce constructeur statique. Sinon, les initialiseurs de champ statique sont exécutés à un moment dépendant de l'implémentation avant la première utilisation d'un champ statique de cette classe.

dire Ils ne garantissent que vous obtenez est que cela arrive avant que le champ instance est lu. Mais cela peut arriver beaucoup plus tôt.

Si vous voulez garantir que ce qu'il ne fonctionne pas plus tôt que le premier accès de la propriété que vous aurez besoin d'ajouter un constructeur statique (potentiellement vide):

Le constructeur statique pour un Le type de classe fermée s'exécute au plus une fois dans un domaine d'application donné. L'exécution d'un constructeur statique est déclenchée par l'apparition du premier des événements suivants dans un domaine d'application:
· Une instance du type de classe est créée.
· Les membres statiques du type de classe sont référencés.


En tant que nœud de côté: je remarquai que lors de l'utilisation DI il est rarement nécessaire d'utiliser un singleton réelle. Dire simplement à DI qu'il devrait créer une seule instance suffit. C'est très bien si vous décidez plus tard que vous voulez plus d'une instance, puisque le fait que ce soit un singleton n'est pas cuit dans tout le code qui l'utilise.

6

L'instance singleton sera chargée en mémoire lorsque la classe elle-même est chargée, c'est-à-dire lorsque la méthode qui pourrait l'appeler commence l'exécution. La ligne réelle qui appelle dans la classe n'a pas à exécuter réellement. Ceci est une très légère distinction, mais peut créer des problèmes difficiles à déboguer lorsqu'un constructeur statique ou un initialiseur de champ statique peut lancer une erreur (que vous n'avez pas ici).

Ceci est corrigé dans .NET 4 avec la nouvelle implémentation Lazy<T>.

http://msmvps.com/blogs/jon_skeet/archive/2010/01/26/type-initialization-changes-in-net-4-0.aspx

public sealed class Singleton 
{ 
    private static readonly Lazy<Singleton> lazy = 
     new Lazy<Singleton>(() => new Singleton()); 

    public static Singleton Instance { get { return lazy.Value; } } 

    private Singleton() 
    { 
    } 
} 

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