Rea*_*lar 30 c# singleton design-patterns
这就是我编写单例类的方法.
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() { .... }
}
Run Code Online (Sandbox Code Playgroud)
单身模式存在以下挑战.
private
或protected
.MyAbstractSingletonClass
.我在许多类上使用这种模式,并且总是必须编写相同的代码.我怎么能写出一些我需要单身时可以重复使用的东西?
BTo*_*TKD 51
您可以结合使用自引用泛型类型约束和" 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;
}
}
}
Run Code Online (Sandbox Code Playgroud)
您的子课程将如下所示:
public class MyChildSingleton : SingletonBase<MyChildSingleton>
{
//Done!
}
Run Code Online (Sandbox Code Playgroud)
当然,如果你希望你的单例是通用的,你也应该稍微更改你的"创建单例实例"代码,使用" 双重检查锁 "模式或Lazy类,使其成为线程安全的.
最重要的警告:如果使用此方法,"new()"约束几乎可以确保您的类始终具有公共的无参数构造函数.这意味着你的最终用户可以随时调用,new MyChildSingleton()
如果他们真的想要,完全绕过你的单例实例.你的单身人士将"按惯例",而不是严格执行.为了解决这个问题需要更多的工程.在上面的场景中,约定似乎是您应该将静态实例命名为" Default
"而不是" Instance
.".这巧妙地传达了这样一个事实:你的类提供了一个"建议的"单例实例,但使用它在技术上是可选的.
我已经尝试严格执行单例模式,最终结果是使用反射来手动调用私有构造函数.您可以在此处查看我的完整代码尝试.
真正的解决方案是从BTownTKD的方法开始,但使用Activator.CreateInstance方法扩充它,它允许您的子类保留私有构造函数.
家长班
public abstract class BaseSingleton<T> where T :
BaseSingleton<T>
{
private static readonly ThreadLocal<T> Lazy =
new ThreadLocal<T>(() =>
Activator.CreateInstance(typeof(T), true) as T);
public static T Instance => Lazy.Value;
}
Run Code Online (Sandbox Code Playgroud)
儿童班
public sealed class MyChildSingleton : BaseSingleton<MyChildSingleton>
{
private MyChildSingleton() { }
}
Run Code Online (Sandbox Code Playgroud)
添加到BTownTKD的答案,在运行时限制构造函数调用实际上非常简单(在编译时不确定).您所做的就是在SingletonBase中添加一个受保护的构造函数,如果_instance不为null,则抛出异常.即使构造函数是从外部调用的第一个东西,也会抛出异常.
我设法在单独的基础上应用这个技术,并且如下所述使它变得懒惰和线程安全:http://csharpindepth.com/Articles/General/Singleton.aspx
结果(使用说明):
/// <summary>
/// Generic singleton class, providing the Instance property, and preventing manual construction.
/// Designed as a base for inheritance trees of lazy, thread-safe, singleton classes.
/// Usage:
/// 1. Sub-class must use itself, or its sub-class, as the type parameter S.
/// 2. Sub-class must have a public default constructor (or no constructors).
/// 3. Sub-class might be abstract, which requires it to be generic and demand the generic type
/// have a default constructor. Its sub-classes must answer all these requirements as well.
/// 4. The instance is accessed by the Instance getter. Using a constructor causes an exception.
/// 5. Accessing the Instance property in an inner initialization in a sub-class constructor
/// might cause an exception is some environments.
/// </summary>
/// <typeparam name="S">Lowest sub-class type.</typeparam>
public abstract class Singleton<S> where S : Singleton<S>, new()
{
private static bool IsInstanceCreated = false;
private static readonly Lazy<S> LazyInstance = new Lazy<S>(() =>
{
S instance = new S();
IsInstanceCreated = true;
return instance;
});
protected Singleton()
{
if (IsInstanceCreated)
{
throw new InvalidOperationException("Constructing a " + typeof(S).Name +
" manually is not allowed, use the Instance property.");
}
}
public static S Instance
{
get
{
return LazyInstance.Value;
}
}
}
Run Code Online (Sandbox Code Playgroud)
我必须说我没有进行密集的多线程测试,但正如一些人已经说过的那样,你总是可以使用旧的双重检查技巧.
归档时间: |
|
查看次数: |
20396 次 |
最近记录: |