如何抽象单例类?

问题描述 投票:30回答:9

这是我编写单例类的方式。

public class MyClass
{
    /// <summary>
    /// Singleton
    /// </summary>
    private static MyClass instance;

    /// <summary>
    /// Singleton access.
    /// </summary>
    public static MyClass Instance
    {
        get
        {
            if (_instance == null)
            {
                _instance = new MyClass();
            }
            return _instance;
        }
    }

    private MyClass() { .... }
}

如何创建可重用的单例模式?

单一模式提出以下挑战。

  • 构造函数是privateprotected
  • 基类无法实例化继承的类。因此,您可以重用常见的摘要MyAbstractSingletonClass
  • 它必须具有本地只读属性才能获取实例。

问题

我在许多类上使用此模式,总是必须编写相同的代码。每当我需要单例时,如何编写可以重用的内容?

c# design-patterns singleton
9个回答
55
投票

您可以结合使用self-referencing generic type constraint和“ new()”类型约束来实现。

“ new”约束确保任何子类始终具有无参数的构造函数,因此_instance = new T();将始终有效。

自引用类型约束确保“实例”静态属性始终返回正确的类型;不是“基本”类型。您的单例基类如下所示:

public abstract class SingletonBase<T> 
    where T : SingletonBase<T>, new()
{
    private static T _instance = new T();
    public static T Instance
    {
        get
        {                
            return _instance;
        }   
    }
}

您的子类将如下所示:

public class MyChildSingleton : SingletonBase<MyChildSingleton>
{
    //Done!
}

当然,如果您希望单例成为通用对象,还应该稍微更改“创建单例实例”代码,以使用“ double-check lock”模式或Lazy类使其成为线程-安全。

大警告:如果使用此方法,则“ new()”约束将确保您的类始终具有公共的,无参数的构造函数。这意味着您的最终用户如果真的愿意,总是可以只调用new MyChildSingleton(),而完全绕开了您的单例实例。您的单例将是“按惯例”,而不是严格执行。要解决此问题,将需要更多的工程设计。在上述情况下,惯例似乎是您应该将静态实例命名为“ Default”而不是“ Instance”。这巧妙地传达了一个事实,即您的类提供了“建议的”单例实例,但使用它在技术上是可选的。]

我已经尝试过严格实施单例模式,最终结果是使用反射来手动调用私有构造函数。您可以看到我的完整代码尝试here


7
投票

真正的解决方案是从BTownTKD的方法开始,但通过Activator.CreateInstance方法进行增强,该方法允许您的子类保留私有构造函数。


5
投票

[添加到BTownTKD的答案中,在运行时限制构造函数调用实际上非常简单(不确定在编译中可能)。您要做的就是在SingletonBase中添加一个受保护的构造函数,如果_instance不为null,则抛出异常。即使构造函数是从外部调用的第一件事,也会引发异常。


3
投票

您是正确的-就目前而言,您无法实现这一目标。但是您可以使用泛型来实现它,请注意,通过这种方法,您将获得每个唯一派生类型的一个单例实例


2
投票

我相信使用@Buvy的解决方案,您将在每个线程中获得一个实例,这可能是他想要的。您将需要对其进行一些修改以在线程之间获得单个实例。


1
投票

简单的答案是您不能在基类中实现单例模式。


1
投票

我建议的示例:


0
投票

我最近对相关问题提出了这个答案:


0
投票

线程安全的lockless pattern的通用,简化的实现:

© www.soinside.com 2019 - 2024. All rights reserved.