问题
I would like to find a concise C# implementation of the Singleton pattern, and I am wondering if it should support the following scenario. What if my singleton's private constructor, as part of initializing the instance, calls a constructor that itself tries to access the singleton currently being initialized? This is what I meant by reentrancy in this question's title. Some would say that a constructor shouldn't do anything complex enough that could lead to this occurring. But what if, due to some future code change within the invoked constructors, it does happen?
I looked through the various answers to this question. I am impressed by the brevity of using Lazy<T>
. In the use case I am looking it, it throws an exception which is much better than constructing two instances of the singleton. But alas, in throwing the exception it crashes the app which means it does not support the target scenario.
class Apple
{
static readonly Lazy<Apple> instance = new Lazy<Apple>( () => new Apple(), true );
public static Apple Instance { get { return instance.Value; } }
private Apple()
{
// Call other methods which might access Instance...
var testGet = Instance;
}
}
So I have the idea to instead do the following.
class Banana
{
static Banana instance;
public static Banana Instance { get { return instance ?? new Banana(); } }
private Banana()
{
instance = this;
// Then call other methods which might access Instance...
var testGet = Instance;
}
}
It supports the target scenario, but is anything wrong with it? Is there a better solution?
Please note the following before posting an answer. Like many people, I still consider Singleton as a pattern. Many DI enthusiasts like calling it an anti-pattern. In the context of a project that relies on DI/IoC, this is a reasonable assertion. Outside of that context, however, Singleton is still a valid design pattern. I do not use DI and am not interested in discussing its merit points here. Please do not post an answer below if it will refer to Singleton as an "anti-pattern", or if it will offer "dependency injection" as the solution. Thanks in advance.
回答1:
Although Singleton may not be considered an anti-pattern, accessing members of an instance before that instance is fully constructed is an anti-pattern. You can't guarantee that code external to the class being initialized doesn't try using some uninitialized state. So the scenario in question should not be supported. If code that attempts to access the singleton is later added to the constructors invoked by the singleton's constructor, then that should trigger a redesign.
Using Lazy<T>
as Apple
demonstrates is the better approach since it throws an exception on re-entrance rather than accessing an incomplete instance. Lazy<T>
additionally supports access from multiple threads, if needed.
来源:https://stackoverflow.com/questions/18855036/concise-singleton-impl-that-supports-reentrancy