【问题标题】:What is a singleton in C#?C# 中的单例是什么?
【发布时间】:2011-01-10 11:20:17
【问题描述】:

什么是单例,我应该什么时候使用它?

【问题讨论】:

  • 另外,Singleton 是 OO 编程中最广泛使用和滥用的设计模式之一。
  • @Fabiano:因为它有一种创建毫无意义的耦合的方法(我怎样才能让XY 交谈?只需让Y 成为单身人士!),其中反过来会导致测试/调试困难和编程风格。有时单例是必要的;大多数时候,不是。
  • 这是我的标准电话面试问题之一。正确答案是:从不。
  • @jonnii 很好,它有助于警告潜在的开发人员那里的老板是什么样的!

标签: c# .net singleton


【解决方案1】:

单例是一个类,它只允许创建自己的一个实例 - 并提供对所述实例的简单、轻松的访问。单例前提是跨软件开发的一种模式。

有一个 C# 实现 "Implementing the Singleton Pattern in C#" 涵盖了您需要了解的大部分内容 - 包括一些关于线程安全的好建议。

说实话,很少需要实现单例 - 在我看来,它应该是你应该注意的事情之一,即使它不经常使用。

【讨论】:

  • 不错的教程,但天哪,他们对代码缩进做了什么
  • 这里有一个更直接的链接,指向我认为是 2020 年的理想实施。即“using .NET 4's Lazy<T> type”,以及指向 Microsoft Doc 的Lazy&lt;T&gt; 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 docsthis 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&lt;T&gt; 创建您的Singleton

            See here 使用Lazy&lt;T&gt; 的更详细示例

            【讨论】:

              【解决方案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()
                        {
                        }
                    }
                    

                    【讨论】:

                      猜你喜欢
                      • 2014-09-11
                      • 1970-01-01
                      • 2020-08-05
                      • 2018-01-12
                      • 1970-01-01
                      • 2010-10-12
                      • 1970-01-01
                      • 2010-09-13
                      相关资源
                      最近更新 更多