You can achieve this using a combination of a self-referencing generic type constraint, and a "new()" type constraint.
The "new" constraint ensures that any child class will always have a parameterless constructor, so _instance = new T();
will always work.
The self-referencing type constraint ensures that the "Instance" static property always returns the correct Type; not the "base" type. Your singleton base class would look something like this:
public abstract class SingletonBase<T>
where T : SingletonBase<T>, new()
{
private static T _instance = new T();
public static T Instance
{
get
{
return _instance;
}
}
}
Your child classes will look like this:
public class MyChildSingleton : SingletonBase<MyChildSingleton>
{
//Done!
}
Of course, if you want your singleton to be general-purpose, you should also change your "create singleton instance" code slightly, to use the "double-check lock" pattern, or the Lazy class, to make it thread-safe.
The big caveat: if you use this method, the "new()" constraint pretty much ensures that your class will always have a public, parameterless constructor. That means your end-users could always just call new MyChildSingleton()
if they really wanted, bypassing your singleton instance entirely. Your singleton would be "by convention," instead of strictly enforced. To get around this would take a bit more engineering. In the above scenario, the convention seems to be that you should name your static instance "Default
" instead of "Instance
." This subtly conveys the fact that your class offers a 'suggested' singleton instance, but using it is technically optional.
I've made some attempts to strictly enforce the singleton pattern, and the end result was to use reflection to manually invoke a private constructor. You can see my full code attempt here.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…