C# 中的单例是啥?
Posted
技术标签:
【中文标题】C# 中的单例是啥?【英文标题】:What is a singleton in C#?C# 中的单例是什么? 【发布时间】:2011-01-10 11:20:17 【问题描述】:什么是单例,我应该什么时候使用它?
【问题讨论】:
可能重复:***.com/questions/246710/… 另外,Singleton 是 OO 编程中最广泛使用和滥用的设计模式之一。 @F***o:因为它有一种创建毫无意义的耦合的方法(我怎样才能让X
与Y
交谈?只需让Y
成为单身人士!),其中反过来会导致测试/调试困难和编程风格。有时单例是必要的;大多数时候,不是。
这是我的标准电话面试问题之一。正确答案是:从不。
@jonnii 很好,它有助于警告潜在的开发人员那里的老板是什么样的!
【参考方案1】:
单例是一个类,它只允许创建自己的一个实例 - 并提供对所述实例的简单、轻松的访问。单例前提是跨软件开发的一种模式。
有一个 C# 实现 "Implementing the Singleton Pattern in C#" 涵盖了您需要了解的大部分内容 - 包括一些关于线程安全的好建议。
说实话,很少需要实现单例 - 在我看来,它应该是你应该注意的事情之一,即使它不经常使用。
【讨论】:
不错的教程,但天哪,他们对代码缩进做了什么 这里有一个更直接的链接,指向我认为是 2020 年的理想实施。即“using .NET 4's Lazy<T> type”,以及指向 Microsoft Doc 的Lazy<T> Class
的链接。
【参考方案2】:
您要求使用 C#。简单的例子:
public class Singleton
private Singleton()
// Prevent outside instantiation
private static readonly Singleton _singleton = new Singleton();
public static Singleton GetSingleton()
return _singleton;
【讨论】:
不是线程安全的。两个线程可以同时调用并且可以创建两个单独的对象。 @Alagesan Palani,确实你是对的。我不精通类级初始化的低级细节,但我认为我所做的更改解决了线程安全问题。 当然,我不是说你错了。我在给读者一个关于线程安全的提示,以便他们在必须处理它时会小心。 不,我认为您的评论很重要。假设一个单例应该交付一个——而且只有一个——实例,这里的竞争条件打开了交付多个实例的可能性。现在查看带有静态字段初始化的版本。如果我正确阅读了the docs 和this SO answer,我相信这可以解决线程安全问题。 它仍然不是线程安全的。将字段更改为静态不会使其成为线程安全的。您需要添加一个静态的构造函数,然后它将是线程安全的。【参考方案3】:它是什么: 在应用程序的整个生命周期中只有一个持久实例的类。见Singleton Pattern。
什么时候应该使用它:尽可能少。只有当你绝对确定你需要它时。我不愿意说“从不”,但通常有更好的选择,例如依赖注入或简单的静态类。
【讨论】:
我不确定静态类是不是比单例更好的选择......这真的取决于情况和语言。 静态类的行为方式与单例不同,单例可以作为参数传递给方法,而静态类则不能。 同意 marcgg - 我不认为静态类是单例的好替代品,因为您仍然存在提供替代品的问题,例如在测试依赖于此类的组件期间。但我也看到了不同的用途,静态类通常用于独立于状态的独立实用程序函数,其中单例是实际的类实例,它通常会存储状态。我完全同意改用 DI,然后告诉您的 DI 容器您希望它只使用该类的单个实例。 我对这个答案投了反对票,因为它没有给我关于何时使用它的信息。对于刚接触单身人士的人来说,“仅当您需要时”并没有真正为我提供任何信息。 @Adkins:DI 代表依赖注入,即通过(通常)构造函数或公共属性传入任何类依赖项。 DI 本身并不能解决“距离”问题,但它通常与知道如何自动初始化任何依赖项的控制反转 (IoC) 容器一起实现。因此,如果您正在创建一个 Singleton 来解决“X 不知道如何查找/与 Y 对话”问题,那么 DI 和 IoC 的组合可以通过更松散的耦合来解决相同的问题。【参考方案4】:在c#中实现单例的另一种方式,我个人更喜欢这种方式,因为您可以将单例类的实例作为属性而不是方法来访问。
public class Singleton
private static Singleton instance;
private Singleton()
public static Singleton Instance
get
if (instance == null)
instance = new Singleton();
return instance;
//instance methods
但是,据我所知,这两种方式都被认为是“正确的”,所以这只是个人风格的事情。
【讨论】:
不是线程安全的。两个线程可以同时调用并且可以创建两个单独的对象。【参考方案5】:using System;
using System.Collections.Generic;
class MainApp
static void Main()
LoadBalancer oldbalancer = null;
for (int i = 0; i < 15; i++)
LoadBalancer balancerNew = LoadBalancer.GetLoadBalancer();
if (oldbalancer == balancerNew && oldbalancer != null)
Console.WriteLine("0 SameInstance 1", oldbalancer.Server, balancerNew.Server);
oldbalancer = balancerNew;
Console.ReadKey();
class LoadBalancer
private static LoadBalancer _instance;
private List<string> _servers = new List<string>();
private Random _random = new Random();
private static object syncLock = new object();
private LoadBalancer()
_servers.Add("ServerI");
_servers.Add("ServerII");
_servers.Add("ServerIII");
_servers.Add("ServerIV");
_servers.Add("ServerV");
public static LoadBalancer GetLoadBalancer()
if (_instance == null)
lock (syncLock)
if (_instance == null)
_instance = new LoadBalancer();
return _instance;
public string Server
get
int r = _random.Next(_servers.Count);
return _servers[r].ToString();
我从dofactory.com 获取代码,没什么特别的,但是我发现这比 Foo 和 Bar 的示例好得多 另外 Judith Bishop 关于 C# 3.0 设计模式的书有关于 mac 中的活动应用程序的示例码头。
如果您查看代码,我们实际上是在 for 循环上构建新对象,这样会创建新对象但会重用实例,因此 oldbalancer 和 newbalancer 具有相同的实例,如何?其原因在于函数 GetLoadBalancer() 上使用了 static 关键字,尽管服务器值不同,即随机列表,但 GetLoadBalancer() 上的静态值属于类型本身而不是特定对象。
这里还有double check locking
if (_instance == null)
lock (syncLock)
if (_instance == null)
来自 MSDN
lock 关键字确保一个线程不进入代码的临界区,而另一个线程在临界区。如果另一个线程试图输入一个锁定的代码,它会等待、阻塞,直到对象被释放。
所以每次互斥锁都会发出,即使它不需要,也是不必要的,所以我们有空检查。
希望它有助于清除更多。
如果我的理解方向错误,请发表评论。
【讨论】:
【参考方案6】:单例(这与 C# 无关,它是一种 OO 设计模式)是指您希望在整个应用程序中只允许创建一个类的实例。使用通常包括全球资源,尽管我会根据个人经验说,它们通常是巨大痛苦的根源。
【讨论】:
【参考方案7】:虽然单例只能有一个实例,但它与静态类不同。静态类只能包含静态方法并且永远不能被实例化,而单例的实例可以像任何其他对象一样使用。
【讨论】:
【参考方案8】:这是一种设计模式,并不特定于 c#。有关它的更多信息,请访问互联网和 SO,例如 wikipedia article。
在软件工程中,单例 模式是一种设计模式 用于限制 a 的实例化 归类为一个对象。这很有用 当只需要一个对象时 协调整个系统的行动。 这个概念有时被概括 运行更多的系统 当只有一个对象时有效 存在,或限制 实例化到一定数量的 对象(例如,五个)。有人认为 一个反模式,判断它是 过度使用,引入不必要的 在唯一的情况下的限制 类的实例实际上不是 必需,并引入全局状态 进入应用程序。
如果你想要一个只能实例化一次的类,你应该使用它。
【讨论】:
【参考方案9】:我用它来查找数据。从数据库加载一次。
public sealed class APILookup
private static readonly APILookup _instance = new APILookup();
private Dictionary<string, int> _lookup;
private APILookup()
try
_lookup = Utility.GetLookup();
catch
static APILookup()
public static APILookup Instance
get
return _instance;
public Dictionary<string, int> GetLookup()
return _lookup;
【讨论】:
【参考方案10】:什么是单例: 它是一个类,它只允许创建它自己的一个实例,并且通常提供对该实例的简单访问。
什么时候应该使用: 视情况而定。
注意:请不要在数据库连接上使用,详细答案请refer@Chad Grant 的回答
这是Singleton
的简单示例:
public sealed class Singleton
private static readonly Singleton instance = new Singleton();
// Explicit static constructor to tell C# compiler
// not to mark type as beforefieldinit
static Singleton()
private Singleton()
public static Singleton Instance
get
return instance;
您也可以使用Lazy<T>
创建您的Singleton
。
See here 使用Lazy<T>
的更详细示例
【讨论】:
【参考方案11】:这里是单例:http://en.wikipedia.org/wiki/Singleton_pattern
我不懂 C#,但实际上所有语言都一样,只是实现不同。
如果可能,您通常应该避免使用单例,但在某些情况下它非常方便。
对不起我的英语;)
【讨论】:
你的英语还行:)【参考方案12】:我知道现在回答这个问题已经很晚了,但是使用 Auto-Property 你可以这样做:
public static Singleton Instance get; = new Singleton();
Singleton
是你的类并且可以通过,在本例中为只读属性 Instance
。
【讨论】:
【参考方案13】:线程安全单例,不使用锁和惰性实例化。
此实现具有静态构造函数,因此每个应用程序域仅执行一次。
public sealed class Singleton
static Singleton()
private Singleton()
public static Singleton Instance get; = new Singleton();
【讨论】:
【参考方案14】:E.X 可以使用 Singleton 来获取需要注入的全局信息。
就我而言,我将记录的用户详细信息(用户名、权限等)保存在全局静态类中。当我尝试实现单元测试时,我无法将依赖项注入到 Controller 类中。因此,我已将我的静态类更改为单例模式。
public class SysManager
private static readonly SysManager_instance = new SysManager();
static SysManager()
private SysManager()
public static SysManager Instance
get return _instance;
http://csharpindepth.com/Articles/General/Singleton.aspx#cctor
【讨论】:
【参考方案15】:来自Implementing the Singleton Pattern in C#的第四版
您可以使用此实现(并且仅此实现)的一个捷径是使实例成为公共静态只读变量,并完全摆脱该属性。这使得基本的骨架代码非常小!
public sealed class Singleton
public static readonly Singleton Instance = new Singleton();
static Singleton()
private Singleton()
【讨论】:
以上是关于C# 中的单例是啥?的主要内容,如果未能解决你的问题,请参考以下文章