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

Rob*_*elo 6 c# inheritance singleton

我发现在C#中你可以实现一个Singleton类,如下所示:

class Singleton
{

    private static Singleton _instance;

    public static Singleton Instance
    {
        get { return _instance ?? (_instance = new Singleton()); }
    }

    protected Singleton() { }
}
Run Code Online (Sandbox Code Playgroud)

适用于类型实例Singleton,即:

var a = Singleton.Instance;
var b = Singleton.Instance;
Console.WriteLine(ReferenceEquals(a, b)); //Prints True.
Run Code Online (Sandbox Code Playgroud)

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

class A:Singleton
{ ... }
A a = A.Instance;
Run Code Online (Sandbox Code Playgroud)

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

  • 派生类可以实现自己的构造函数并松散Singleton Pattern.
  • 如果存在另一个实例,Singleton则派生类将引用较少派生的实例

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

Moo*_*ice 18

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

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

并由此得出:

public class SingletonA : Singleton<SingletonA> { /* .... */ }
public class SingletonB : Singleton<SingletonB> { /* .... */ }
Run Code Online (Sandbox Code Playgroud)

但是,我个人并不主张这种单身方法.他们确实有他们的(罕见的)用途,但他们可能会变得更加痛苦 - 转向美化的全球变量容器.

另外,请注意线程安全.

  • @ Moo-Juice确定,修正了这个错误只剩下一个问题:你的`Singleton <T>`类有一个`new()`约束,这意味着`T`必须有一个公共构造函数.因此,像SingletonA:Singleton <SingletonA>这样的类可以简单地用new创建.这不是打败单身人士的目的吗? (4认同)
  • 我有点困惑,您的通用 `Singleton&lt;T&gt;` 类要求 `T` 具有公共无参数构造函数,因此实际上没有一个继承的类被强制为单例。并且`GetInstance` 方法是非静态的(显然)所以为了调用它你需要一个实例,它应该通过`GetInstance` 获得。 (3认同)
  • 我还要谨慎使用Instance属性而不是GetInstance()方法.如果由于代码中构造的实例的副作用而在断点点击时将鼠标悬停在调试器中的Instance属性上,可能会发生一些有趣的事情.当然,a)避免使用Singleton模式和b)避免其构造函数中的副作用要好得多. (2认同)

Jon*_*eet 5

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

好吧,您可以在构造函数中进行某种检查:

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

然而,这似乎相当没有意义。你的基类实际上是要实现什么?

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

在我看来,“我是对象实际类型的单例”一开始并不是继承的合适基础,坦率地说,无论如何我都会尽量避免单例模式。

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