问题
This is my abstract class which must be derived each time I want to make a Singleton:
public abstract class Singleton<T> where T : Singleton<T>
{
private static readonly Lazy<T> _instance = new Lazy<T>(() =>
{
var constructor = typeof(T).GetConstructor(BindingFlags.NonPublic |
BindingFlags.Instance, null, new Type[0], null);
return (T)constructor.Invoke(null);
});
public static T Instance { get { return _instance.Value; } }
public Singleton() { }
}
So, every time I need to follow the Singleton design pattern, I can just make this:
sealed class Server : Singleton<Server>
{
private Server() { }
...
}
Is this completely right, and, if not, why?
Edit:
- Added private constructor on derived class example and invoking on abstract base.
Edit:
- Reworked type parameter initialization.
回答1:
Self implemented singletons are an anti-pattern. The need to inherit, and lock your classes into a specific form goes away if you just implement a factory:
public class Server {} //Not coupled to any inheritance hierarchy.
public class Factory
{
private readonly Lazy<Server> _server = new Lazy<Server>(() => new Server());
public Server Server { get { return _server.Value; } }
}
However, you're really using the factory as a service locator and service locator is also considered an anti-pattern as you can easily just use DI to inject the Server instance into your consuming classes.
public class MyServerConsumer
{
public MyServerConsumer(Server server)
{
//Do stuff.
}
}
Windsor style registration:
...
Component.For<Server>();
...
Notice that the word singleton is never mentioned? You still get 'a single instance of an object', but you don't have to write code to maintain that relationship, and your classes are not constrained and corrupted by the concept of 'singleton' from the start
回答2:
No you can't because when you want to use new T()
you should have a public constructor for it, and it's different from singleton definition. because in singleton you should have a private constructor, and in this case (public one) everyone can create new instance of your object and it's not a singleton.
回答3:
This approach you are using has a significant downside. You couple your classes to the Singleton class. Apart from being generally not-SOLID, you lose the ability to derive from a class you might need to (if the class is not Singleton).
The best practice is that you need to use Dependency Injection and IoC container. All IoC containers allow you to specify weather the class is a Singleton or not.
This way the class is completely oblivious to the fact that it is instantiated as a Singleton, and it is easy to change this on-the-fly without changing dependencies.
回答4:
C# gives you no guarantee of when the static field _instance
will be created. This is because the C# standard simply states that classes (which are marked in the IL as BeforeFieldInit) can have their static fields initialized any time before the field is accessed. This means that they may be initialized on first use, they may be initialized at some other time before, you can't be sure when.
Drop Lazy usage
I suggest to drop the Lazy
construction and introduce a static ctor to create the instance. This way you take advantage of the C# standard's BeforeFieldInit
, but you will lose lazyness. Although it is lazy in some way, it's not created before the type is used. Which is good, since most singletons are used when referenced anyway.
public abstract class Singleton<T> where T : class, new()
{
private static readonly T _instance;
public static T Instance { get { return _instance; } }
public static Singleton()
{
_instance = new T();
}
}
Public ctor problem
The problem you have now is that the new T()
construction forces you to have a public ctor. Which isn't really nice for singletons. You could use a private ctor that you invoke via reflection to solve this.
回答5:
That's just a comment on pjvds' reply (I couldn't comment in the regular way because I don't have enough points...).
Instead of using a private constructor via reflection, you can have a private init method, and call it after the "new T()" in the static Singlton method.
来源:https://stackoverflow.com/questions/8036883/can-i-define-an-abstract-class-for-all-derived-singletons-in-this-way