在C#中,什么是一个好的线程安全单例模板模式
我有以下C#单例模式,有没有改进它的方法?
public class Singleton<T> where T : class, new() { private static object _syncobj = new object(); private static volatile T _instance = null; public static T Instance { get { if (_instance == null) { lock (_syncobj) { if (_instance == null) { _instance = new T(); } } } return _instance; } } public Singleton() { } }
首选用法示例:
class Foo : Singleton<Foo> { }
相关 :
.NET的一个明显的单一实现?
根据Jon Skeet在C#中实现Singleton模式的说法,你发布的代码实际上被认为是不好的代码,因为在ECMA CLI标准中进行检查时,代码会显示出来。
还要注意:每当你用一种新型的T来实例化你的对象时,它就成为另一个事例; 它不会反映在你原来的单身人士。
这段代码不会编译,你需要在T上有“类”约束。
此外,此代码需要目标类上的公共构造函数,这对单例不好,因为在编译时您不能控制仅通过实例属性(或字段)获取(单个)实例。 如果除Instance之外没有其他静态成员,则可以这样做:
class Foo { public static readonly Instance = new Foo(); private Foo() {} static Foo() {} }
它是线程安全的(由CLR保证)和懒惰(实例是第一次访问types创build的)。 有关BeforeFieldInit的更多讨论以及为什么我们需要静态构造函数,请参阅http://www.yoda.arachsys.com/csharp/beforefieldinit.html 。
如果你想在types上有其他的公共静态成员,但只有在访问实例时创build对象,你可以创build嵌套types,就像在http://www.yoda.arachsys.com/csharp/singleton.html
Courtesy of Judith Bishop, http://patterns.cs.up.ac.za/
这个单例模式实现确保了懒惰的初始化。
// Singleton PatternJudith Bishop Nov 2007 // Generic version public class Singleton<T> where T : class, new() { Singleton() { } class SingletonCreator { static SingletonCreator() { } // Private object instantiated with private constructor internal static readonly T instance = new T(); } public static T UniqueInstance { get { return SingletonCreator.instance; } } }
这是我使用.NET 4的一点
public class Singleton<T> where T : class, new() { Singleton (){} private static readonly Lazy<T> instance = new Lazy<T>(()=> new T()); public static T Instance { get { return instance.Value; } } }
在不同的线程上的这个答案的更多细节: 如何在C#中实现一个单身?
但是线程不使用generics 。
我不认为你真的想“烧你的基类”,这样你可以保存2行代码。 你并不需要一个基类来实现单例。
每当你需要一个单身人士,只要这样做:
class MyConcreteClass { #region Singleton Implementation public static readonly Instance = new MyConcreteClass(); private MyConcreteClass(){} #endregion /// ... }
public sealed class Singleton { private static readonly Singleton instance = new Singleton(); private Singleton(){} public static Singleton Instance { get { return instance; } } }
.NET在初始化顺序方面没有任何歧义 。 但是这提出了线程问题。
我正在寻找一个更好的Singleton模式,并喜欢这个。 所以移植到VB.NET,可以为其他人使用:
Public MustInherit Class Singleton(Of T As {Class, New}) Public Sub New() End Sub Private Class SingletonCreator Shared Sub New() End Sub Friend Shared ReadOnly Instance As New T End Class Public Shared ReadOnly Property Instance() As T Get Return SingletonCreator.Instance End Get End Property End Class
根据要求,从我原来的答复交叉发布到另一个问题。
我的版本使用reflection,与派生类中的非公共构造函数一起工作,显然是懒惰的实例化(根据我在下面链接的文章):
public class SingletonBase<T> where T : class { static SingletonBase() { } public static readonly T Instance = typeof(T).InvokeMember(typeof(T).Name, BindingFlags.CreateInstance | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, null, null) as T; }
我几年前就select了这个技术,不知道我的技术是多less,但是如果不是我,那么在代码上search就可能find技术的原始来源。
这是代码的最古老的来源,我可以find不是我发布的代码 。
:/ judith主教的通用“单身”模式似乎有点不对称,它总是可能创buildTtypes的几个实例,因为构造函数必须公开在这个“模式”中使用。 在我看来,它与单例完全没有任何关系,它只是一种工厂,它总是返回相同的对象,但并不是单身…只要一个类可以有多于一个的实例不能是一个单身人士。 任何原因这种模式是最高评价?
public sealed class Singleton { private static readonly Singleton _instance = new Singleton(); private Singleton() { } public static Singleton Instance { get { return _instance; } } }
静态初始化器被认为是线程安全的..我不知道,但你不应该使用单例的成语,如果你包装我的代码超过其不超过3行…并从单身inheritance不使任何意义
试试这个通用的Singleton类,以线程安全和懒惰的方式实现Singletondevise模式(thx to wcell)。
public abstract class Singleton<T> where T : class { /// <summary> /// Returns the singleton instance. /// </summary> public static T Instance { get { return SingletonAllocator.instance; } } internal static class SingletonAllocator { internal static T instance; static SingletonAllocator() { CreateInstance(typeof(T)); } public static T CreateInstance(Type type) { ConstructorInfo[] ctorsPublic = type.GetConstructors( BindingFlags.Instance | BindingFlags.Public); if (ctorsPublic.Length > 0) throw new Exception( type.FullName + " has one or more public constructors so the property cannot be enforced."); ConstructorInfo ctorNonPublic = type.GetConstructor( BindingFlags.Instance | BindingFlags.NonPublic, null, new Type[0], new ParameterModifier[0]); if (ctorNonPublic == null) { throw new Exception( type.FullName + " doesn't have a private/protected constructor so the property cannot be enforced."); } try { return instance = (T)ctorNonPublic.Invoke(new object[0]); } catch (Exception e) { throw new Exception( "The Singleton couldnt be constructed, check if " + type.FullName + " has a default constructor", e); } } } }
Microsoft提供的Double-Check Locking [Lea99]成语与您提供的代码非常相似,不幸的是,ECMA CLI标准对于线程安全代码的清晰视图失败,并且在所有情况下都可能无法正常工作。
在multithreading程序中,不同的线程可以尝试同时实例化一个类。 由于这个原因,依赖if语句检查实例是否为null的Singleton实现将不是线程安全的 。 不要这样写代码!
创build一个线程安全的单例的一个简单而有效的方法是使用一个嵌套类来实例化它。 以下是一个懒惰实例化单例的例子:
public sealed class Singleton { private Singleton() { } public static Singleton Instance { get { return SingletonCreator.instance; } } private class SingletonCreator { static SingletonCreator() { } internal static readonly Singleton instance = new Singleton(); } }
用法:
Singleton s1 = Singleton.Instance; Singleton s2 = Singleton.Instance; if (s1.Equals(s2)) { Console.WriteLine("Thread-Safe Singleton objects are the same"); }
通用解决scheme:
public class Singleton<T> where T : class, new() { private Singleton() { } public static T Instance { get { return SingletonCreator.instance; } } private class SingletonCreator { static SingletonCreator() { } internal static readonly T instance = new T(); } }
用法:
class TestClass { } Singleton s1 = Singleton<TestClass>.Instance; Singleton s2 = Singleton<TestClass>.Instance; if (s1.Equals(s2)) { Console.WriteLine("Thread-Safe Generic Singleton objects are the same"); }
最后,这里有一个相对有用的build议 – 为了避免使用lock关键字可能引起的死锁,考虑添加下面的属性来帮助保护公共静态方法中的代码:
using System.Runtime.CompilerServices; [MethodImpl (MethodImplOptions.Synchronized)] public static void MySynchronizedMethod() { }
参考文献:
- C#食谱(O'Reilly),Jay Hilyard和Stephen Teilhet
- C#3.0devise模式(O'Reilly),Judith Bishop
- CSharp-Online.Net – Singletondevise模式:线程安全Singleton
我非常喜欢你的原始答案 – 唯一缺less的东西(根据blowdart发布的链接)是使_instancevariables不稳定,以确保它实际上已经设置在锁中。 我实际上使用blowdarts解决scheme时,我不得不使用一个单身人士,但我没有任何需要迟到instantiate等
我对确保按需创build实例数据的贡献:
/// <summary>Abstract base class for thread-safe singleton objects</summary> /// <typeparam name="T">Instance type</typeparam> public abstract class SingletonOnDemand<T> { private static object __SYNC = new object(); private static volatile bool _IsInstanceCreated = false; private static T _Instance = default(T);
/// <summary>Instance data</summary> public static T Instance { get { if (!_IsInstanceCreated) lock (__SYNC) if (!_IsInstanceCreated) _Instance = Activator.CreateInstance<T>(); return _Instance; } } }
再说一遍… 🙂
我对确保按需创build实例数据的贡献:
/// <summary>Abstract base class for thread-safe singleton objects</summary> /// <typeparam name="T">Instance type</typeparam> public abstract class SingletonOnDemand<T> { private static object __SYNC = new object(); private static volatile bool _IsInstanceCreated = false; private static T _Instance = default(T); /// <summary>Instance data</summary> public static T Instance { get { if (!_IsInstanceCreated) lock (__SYNC) if (!_IsInstanceCreated) { _Instance = Activator.CreateInstance<T>(); _IsInstanceCreated = true; } return _Instance; } } }
public static class LazyGlobal<T> where T : new() { public static T Instance { get { return TType.Instance; } } private static class TType { public static readonly T Instance = new T(); } } // user code: { LazyGlobal<Foo>.Instance.Bar(); }
要么:
public delegate T Func<T>(); public static class CustomGlobalActivator<T> { public static Func<T> CreateInstance { get; set; } } public static class LazyGlobal<T> { public static T Instance { get { return TType.Instance; } } private static class TType { public static readonly T Instance = CustomGlobalActivator<T>.CreateInstance(); } } { // setup code: // CustomGlobalActivator<Foo>.CreateInstance = () => new Foo(instanceOf_SL_or_IoC.DoSomeMagicReturning<FooDependencies>()); CustomGlobalActivator<Foo>.CreateInstance = () => instanceOf_SL_or_IoC.PleaseResolve<Foo>(); // ... // user code: LazyGlobal<Foo>.Instance.Bar(); }
之前看到一个使用reflection访问私有(或公共)默认构造函数的方法:
public static class Singleton<T> { private static object lockVar = new object(); private static bool made; private static T _singleton = default(T); /// <summary> /// Get The Singleton /// </summary> public static T Get { get { if (!made) { lock (lockVar) { if (!made) { ConstructorInfo cInfo = typeof(T).GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[0], null); if (cInfo != null) _singleton = (T)cInfo.Invoke(new object[0]); else throw new ArgumentException("Type Does Not Have A Default Constructor."); made = true; } } } return _singleton; } } }
我把这个提交给小组。 它似乎是线程安全的,通用的,遵循模式。 你可以从它inheritance。 这是从别人所说的拼凑起来的。
public class Singleton<T> where T : class { class SingletonCreator { static SingletonCreator() { } internal static readonly T Instance = typeof(T).InvokeMember(typeof(T).Name, BindingFlags.CreateInstance | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, null, null) as T; } public static T Instance { get { return SingletonCreator.Instance; } } }
预期实施:
public class Foo: Singleton<Foo> { private Foo() { } }
然后:
Foo.Instance.SomeMethod();
正如在维基百科 :
单例模式是一种将类的实例限制为一个对象的devise模式
我发现没有保证的方式来使用generics,如果你限制了单例本身的实例,如何限制主类的实例化,我认为这是不可能的,并且实现这个简单的模式是不是很难,采用这种方式使用静态构造函数和私人设置:
public class MyClass { private MyClass() { } static MyClass() { Instance = new MyClass(); } public static MyClass Instance { get; private set; } }
要么:
public class MyClass { private MyClass() { } static MyClass() { Instance = new MyClass(); } private static MyClass instance; public static MyClass Instance { get { return instance; } private set { instance = value; } } }
这适用于我:
public static class Singleton<T> { private static readonly object Sync = new object(); public static T GetSingleton(ref T singletonMember, Func<T> initializer) { if (singletonMember == null) { lock (Sync) { if (singletonMember == null) singletonMember = initializer(); } } return singletonMember; } }
用法:
private static MyType _current; public static MyType Current = Singleton<MyType>.GetSingleton(ref _current, () => new MyType());
消费单身人士:
MyType.Current. ...
你并不需要所有这些,C#已经有了一个很好的内置单例模式。
static class Foo
如果你需要比这更有趣的事情,那么你的新单身人士将会有所不同,以至于你的通用模式将变得毫无用处。
编辑:“更有趣的东西”我包括inheritance。 如果你可以从一个单身人士inheritance,那么它不再是一个单身人士。