在c#中实现单例可继承类

本文关键字:可继承 单例 实现 | 更新日期: 2023-09-27 18:16:23

我发现在c#中可以实现一个单例类,如下所示:

class Singleton
{
    private static Singleton _instance;
    public static Singleton Instance => _instance ??= new Singleton();
    protected Singleton() { }
}

适用于类型Singleton的实例,即:

var a = Singleton.Instance;
var b = Singleton.Instance;
Console.WriteLine(ReferenceEquals(a, b)); //Prints True.

但是如果我希望Singleton的派生类也遵循Singleton模式,即:

class A:Singleton
{ ... }
A a = A.Instance;

在这种情况下,Singleton类访问静态成员Instance并创建Singleton实例,这不是目标。此外,这个解决方案有两个主要问题:

    派生类可以实现自己的构造函数,并失去单例模式。
  • 如果存在另一个Singleton实例,则派生类将引用该派生较少的实例

我的问题是:是否有另一种在c#中实现单例类的方法来确保派生类也是单例的?

在c#中实现单例可继承类

忽略通常的"不要使用单例,看看你的设计"参数,你可以想象这样实现一个(假设你的派生类有默认构造函数):

public abstract class Singleton<T> where T : class, new()
{
    private static T _instance;
    public static T GetInstance()
    {
        if(_instance == null)
            _instance = new T();
        return _instance;
    }
}

,这样推导:

public class SingletonA : Singleton<SingletonA> { /* .... */ }
public class SingletonB : Singleton<SingletonB> { /* .... */ }

但是,我个人并不提倡这种单例方法。它们确实有自己的(罕见的)用途,但它们可能更令人讨厌——变成美化的全局变量容器。

还要注意线程安全。

我的问题是:有没有另一种方法来实现一个单例类在c#中确保派生类也是单例的?

你可以在构造函数中做一些检查:

  • this的实际类型为密封
  • this的实际类型是Singleton的直接子类
  • 没有创建该类型的其他实例(通过保持HashSet<Type>)

然而,这似乎毫无意义。您的基类实际要实现的是什么?

单例模式很容易实现正确(你的例子没有,顺便说一下-它不是线程安全的),所以为什么有基类?基类本身不会是单例的(可能会有很多实例——每个子类一个),那么有什么好处呢?

在我看来,"我是对象的实际类型的单例"首先不是继承的适当基础,坦率地说,我无论如何都要尽量避免单例模式。

如果你真的想要一个基类,那应该是因为有一些所有子类自然继承的公共功能。本质上不太可能与这些子类是否是单例有关。