public sealed class Singleton
{
Singleton() {}
public static Singleton Instance
{
get
{
return Nested.instance;
}
}
class Nested
{
// Explicit static constructor to tell C# compiler
// not to mark type as beforefieldinit
static Nested() {}
internal static readonly Singleton instance = new Singleton();
}
}
Je souhaite implémenter le modèle Singleton de Jon Skeet dans mon application actuelle en C #.
J'ai deux doutes sur le code
Comment est-il possible d'accéder à la classe externe à l'intérieur de la classe imbriquée? je veux dire
internal static readonly Singleton instance = new Singleton();
Est-ce quelque chose appelé fermeture?
Je n'arrive pas à comprendre ce commentaire
// Explicit static constructor to tell C# compiler // not to mark type as beforefieldinit
que nous suggère ce commentaire?
Réponses:
Non, cela n'a rien à voir avec les fermetures. Une classe imbriquée a accès aux membres privés de sa classe externe, y compris le constructeur privé ici.
Lisez mon article sur beforefieldinit . Vous pouvez ou non vouloir le constructeur statique sans opération - cela dépend de ce que la paresse garantit dont vous avez besoin. Vous devez savoir que .NET 4 modifie quelque peu la sémantique d'initialisation du type réel (toujours dans la spécification, mais plus paresseux qu'auparavant).
Avez-vous vraiment besoin de ce modèle? Êtes-vous sûr de ne pas pouvoir vous en sortir avec:
la source
Lazy<T>
pour que vous n'ayez pas à déclarer un constructeur statique pour l'BeforeFieldInit
effet secondaire magique ?FieldBeforeInit
vientMahaBharata
deMicrosoft
Concernant la question (1): La réponse de Jon est correcte, car il marque implicitement la classe 'Nested' privé en ne la rendant pas publique ou interne :-). Vous pourriez aussi bien le faire explicitement en ajoutant «privé»:
Concernant la question (2): fondamentalement, ce que la publication sur beforeinitfield et l' initialisation de type vous dit, c'est que si vous n'avez pas de constructeur statique, le runtime peut l'initialiser à tout moment (mais avant de l'utiliser). Si vous avez un constructeur statique, votre code dans le constructeur statique peut initialiser les champs, ce qui signifie que le runtime n'est autorisé à initialiser le champ que lorsque vous demandez le type.
Donc, si vous ne voulez pas que le runtime initialise les champs «proactivement» avant de les utiliser, ajoutez un constructeur statique.
Quoi qu'il en soit, si vous implémentez des singletons, vous voulez soit l'initialiser aussi paresseusement que possible et non pas lorsque le runtime pense qu'il devrait initialiser votre variable - ou vous ne vous en souciez probablement pas. D'après votre question, je suppose que vous les voulez le plus tard possible.
Cela amène à la publication de Jon sur le singleton , qui est l'OMI le sujet sous-jacent de cette question. Oh et les doutes :-)
Je voudrais souligner que son singleton # 3, qu'il a marqué `` faux '', est en fait correct (car le verrouillage implique automatiquement une barrière de mémoire à la sortie ). Il devrait également être plus rapide que singleton # 2 lorsque vous utilisez l'instance plusieurs fois (ce qui est plus ou moins le point d'un singleton :-)). Donc, si vous avez vraiment besoin d'une implémentation de singleton paresseux, j'irais probablement pour celle-ci - pour les raisons simples que (1) c'est très clair pour tout le monde qui lit votre code ce qui se passe et (2) vous savez ce qui se passera avec des exceptions.
Au cas où vous vous poseriez la question: je n'utiliserais jamais le singleton # 6 car cela peut facilement conduire à des blocages et à un comportement inattendu avec des exceptions. Pour plus de détails, voir: le mode de verrouillage de lazy , en particulier ExecutionAndPublication.
la source
Regarding question (1): The answer from Jon is correct ...
Jon Skeet a toujours raison ....