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();
开发者_运维技巧 }
}
I wish to implement Jon Skeet's Singleton pattern in my current application in C#.
I have two doubts on the code
How is it possible to access the outer class inside nested class? I mean
internal static readonly Singleton instance = new Singleton();
Is something called closure?
I am unable to understand this comment
// Explicit static constructor to tell C# compiler // not to mark type as beforefieldinit
what does this comment suggest us?
No, this is nothing to do with closures. A nested class has access to its outer class's private members, including the private constructor here.
Read my article on beforefieldinit. You may or may not want the no-op static constructor - it depends on what laziness guarantees you need. You should be aware that .NET 4 changes the actual type initialization semantics somewhat (still within the spec, but lazier than before).
Do you really need this pattern though? Are you sure you can't get away with:
public sealed class Singleton
{
private static readonly Singleton instance = new Singleton();
public static Singleton Instance { get { return instance; } }
static Singleton() {}
private Singleton() {}
}
Regarding question (1): The answer from Jon is correct, since he implicitly marks the class 'Nested' private by not making it public or internal :-). You might as well do it explicitly by adding 'private':
private class Nested
Regarding question (2): basically what the post about beforeinitfield and type initialization tell you is that if you have no static constructor, the runtime can initialize it at any time (but before you use it). If you do have a static constructor, your code in the static constructor might initialize the fields, which means that the runtime is only allowed to initialize the field when you ask for the type.
So if you don't want the runtime to initialize fields 'proactively' before you use them, add a static constructor.
Either way, if you're implementing singletons you either want it to initialize as lazy as possible and not when the runtime thinks it should initialize your variable -- or you probably just don't care. From your question I suppose you want them as late as possible.
That brings met to Jon's post about singleton's, which is IMO the underlying topic of this question. Oh and the doubts :-)
I'd like to point out that his singleton #3, which he marked 'wrong', is actually correct (because lock's automatically implies a memory barrier on exit). It also should be faster than singleton #2 when you use the instance more than once (which is more or less the point of a singleton :-) ). So, if you really need a lazy singleton implementation, I'd probably go for that one - for the simple reasons that (1) it's very clear for everyone that reads your code what is going on and (2) you know what will happen with exceptions.
In case you're wondering: I would never use singleton #6 because it can easily lead to deadlocks and unexpected behavior with exceptions. For details, see: lazy's locking mode, specifically ExecutionAndPublication.
精彩评论