C#的单例模式
我需要存储一堆需要全局访问的变量,我想知道单例模式是否适用。 从我看过的例子来看,单例模式只是一个无法inheritance的静态类。 但我见过的例子对我的需求来说过于复杂。 什么是最简单的单身人士课程? 难道我不能只用一些变量制作一个静态的密封类吗?
通常,单例不是静态类 – 单例将为您提供类的单个实例 。
我不知道你见过的例子,但通常单例模式在C#中可以非常简单:
public sealed class Singleton { private static readonly Singleton instance = new Singleton(); static Singleton() {} // Make sure it's truly lazy private Singleton() {} // Prevent instantiation outside public static Singleton Instance { get { return instance; } } }
这并不困难。
单例相对于静态成员的优点是类可以实现接口等。有时这很有用 – 但有时候,静态成员确实也会这样做。 此外,以后通常更容易从单例移动到非单例,例如将单例作为“配置”对象传递给依赖类,而不是那些进行直接静态调用的依赖类。
就个人而言,我会尽量避免使用单身人士 – 除了其他任何事情之外,他们会更加努力地进行测试。 它们偶尔会有用。
有几种模式可能适合你,单身人士更糟糕。
注册处
struct Data { public String ProgramName; public String Parameters; } class FooRegistry { private static Dictionary registry = new Dictionary(); public static void Register(String key, Data data) { FooRegistry.registry[key] = data; } public static void Get(String key) { // Omitted: Check if key exists return FooRegistry.registry[key]; } }
好处
- 易于切换到Mock对象进行自动化测试
- 您仍然可以存储多个实例,但如果需要,您只有一个实例。
缺点
- 比Singleton或全局变量略慢
静态类
class GlobalStuff { public static String ProgramName {get;set;} public static String Parameters {get;set;} private GlobalStuff() {} }
好处
- 简单
- 快速
缺点
- 难以动态切换到模拟对象
- 如果需求发生变化,很难切换到另一种对象类型
简单的单身人士
class DataSingleton { private static DataSingleton instance = null; private DataSingleton() {} public static DataSingleton Instance { get { if (DataSingleton.instance == null) DataSingleton.instance = new DataSingleton(); return DataSingleton; } } }
好处
- 没有
缺点
- 难以创建线程安全单例,如果多个线程访问实例,上述版本将失败。
- 很难切换模拟对象
我个人喜欢注册表模式,但YMMV。
您应该看一下dependency injection,因为它通常被认为是最佳实践,但这里要解释的主题太大了:
dependency injection
Singleton不仅仅是一个无法inheritance的静态类。 它是一个常规类,只能实例化一次,每个人都共享该单个实例(并使其线程安全更多的工作)。
Singleton的典型.NET代码如下所示。 这是一个快速示例,绝不是最佳实现或线程安全代码 :
public sealed class Singleton { Singleton _instance = null; public Singleton Instance { get { if(_instance == null) _instance = new Singleton(); return _instance; } } // Default private constructor so only we can instanctiate private Singleton() { } // Default private static constructor private static Singleton() { } }
如果你要沿着你想要的道路走下去,一个静态密封的课程就可以了。
使用C#6自动属性初始化程序。
public sealed class Singleton { private Singleton() { } public static Singleton Instance { get; } = new Singleton(); }
简短而干净 – 我会很高兴听到缺点。
我知道这个问题已经过时了,但这是另一个使用.Net 4.0或更高版本的解决方案(包括.Net Core和.Net Standard)。
首先,定义将转换为Singleton的类:
public class ClassThatWillBeASingleton { private ClassThatWillBeASingleton() { Thread.Sleep(20); guid = Guid.NewGuid(); Thread.Sleep(20); } public Guid guid { get; set; } }
在这个示例类中,我定义了一个睡眠一段时间的构造函数,然后创建一个新的Guid并保存到它的公共属性。 (Sleep仅用于并发测试)
请注意,构造函数是私有的,因此没有人可以创建此类的新实例。
现在,我们需要定义将此类转换为单例的包装器:
public abstract class SingletonBase where T : class { private static readonly Lazy _Lazy = new Lazy (() => { // Get non-public constructors for T. var ctors = typeof(T).GetConstructors(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic); if (!Array.Exists(ctors, (ci) => ci.GetParameters().Length == 0)) throw new InvalidOperationException("Non-public ctor() was not found."); var ctor = Array.Find(ctors, (ci) => ci.GetParameters().Length == 0); // Invoke constructor and return resulting object. return ctor.Invoke(new object[] { }) as T; }, System.Threading.LazyThreadSafetyMode.ExecutionAndPublication); public static T Instance { get { return _Lazy.Value; } } }
请注意,它使用Lazy创建一个字段_Lazy
,它知道如何使用它的私有构造函数实例化一个类。
它定义了一个Property Instance
来访问Lazy字段的Value。
注意传递给Lazy构造函数的LazyThreadSafetyMode
枚举。 它正在使用ExecutionAndPublication
。 因此,只允许一个线程初始化Lazy字段的Value。
现在,我们所要做的就是定义将成为单例的包装类:
public class ExampleSingleton : SingletonBase { private ExampleSingleton () { } }
以下是一个用法示例:
ExampleSingleton.Instance.guid;
并且一个测试断言两个线程将获得Singleton的相同实例:
[Fact()] public void Instance_ParallelGuid_ExpectedReturnSameGuid() { Guid firstGuid = Guid.Empty; Guid secondGuid = Guid.NewGuid(); Parallel.Invoke(() => { firstGuid = Singleton4Tests.Instance.guid; }, () => { secondGuid = Singleton4Tests.Instance.guid; }); Assert.Equal(firstGuid, secondGuid); }
此测试同时调用Lazy字段的值,并且我们要断言将从此属性返回的两个实例(Lazy的值)都相同。
有关此主题的更多详细信息,请访问: C#in Depth
所以,就我而言,这是C#中Singleton模式最简洁,最简单的实现。
http://blueonionsoftware.com/blog.aspx?p=c6e72c38-2839-4696-990a-3fbf9b2b0ba4
然而,我会建议单身人士是非常丑陋的模式……我认为它们是一种反模式。
http://blogs.msdn.com/scottdensmore/archive/2004/05/25/140827.aspx
对我来说,我更喜欢像Repository那样实现IRepository。 您的类可以在构造函数中声明对IRepository的依赖关系,并且可以使用dependency injection或以下方法之一传递它:
使用您的语言function。 大多数简单的线程安全实现是:
public sealed class Singleton { private static readonly Singleton _instance; private Singleton() { } static Singleton() { _instance = new Singleton(); } public static Singleton Instance { get { return _instance; } } }
……最简单的单身人士课程是什么?
只是添加一个可能的解决方案。 我能想到的最简单,最直接和易用的方法是这样的:
//The abstract singleton public abstract class Singleton where T : class { private static readonly Lazy instance = new Lazy ( CreateInstance, true ); public static T Instance => instance.Value; private static T CreateInstance() { return (T)Activator.CreateInstance( typeof(T), true); } } //This is the usage for any class, that should be a singleton public class MyClass : Singleton { private MyClass() { //Code... } //Code... } //Example usage of the Singleton class Program { static void Main(string[] args) { MyClass clazz = MyClass.Instance; } }