这是我编写单例类的方式。
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() { .... }
}
单一模式提出以下挑战。
private
或protected
。MyAbstractSingletonClass
。我在许多类上使用此模式,总是必须编写相同的代码。每当我需要单例时,如何编写可以重用的内容?
您可以结合使用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。
真正的解决方案是从BTownTKD的方法开始,但通过Activator.CreateInstance方法进行增强,该方法允许您的子类保留私有构造函数。
[添加到BTownTKD的答案中,在运行时限制构造函数调用实际上非常简单(不确定在编译中可能)。您要做的就是在SingletonBase中添加一个受保护的构造函数,如果_instance不为null,则抛出异常。即使构造函数是从外部调用的第一件事,也会引发异常。
您是正确的-就目前而言,您无法实现这一目标。但是您可以使用泛型来实现它,请注意,通过这种方法,您将获得每个唯一派生类型的一个单例实例
我相信使用@Buvy的解决方案,您将在每个线程中获得一个实例,这可能是他想要的。您将需要对其进行一些修改以在线程之间获得单个实例。
简单的答案是您不能在基类中实现单例模式。
我建议的示例:
我最近对相关问题提出了这个答案:
线程安全的lockless pattern的通用,简化的实现: