什么是C#中的单身人士?

Ser*_*pia 170 .net c# singleton

非常直截了当的问题.

什么是单身人士,何时应该使用它?

Dan*_*May 135

单例是一个只允许创建自身的一个实例的类 - 并且可以简单,方便地访问所述实例.单例前提是跨软件开发的模式.

有一个C#实现"在C#中实现Singleton模式"涵盖了你需要知道的大部分内容 - 包括一些关于线程安全的好建议.

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

  • 这里有一个更直接的链接,指向我认为的 2020 年理想实现。即“[使用 .NET 4 的 Lazy<T> 类型](https://csharpindepth.com/Articles/Singleton#lazy)”,如以及 [`Lazy<T> Class`](https://learn.microsoft.com/en-us/dotnet/api/system.lazy-1) 的 Microsoft 文档链接。 (3认同)
  • 不错的教程,但天哪,他们对代码缩进做了什么 (2认同)

Chr*_*ons 53

你问了C#.琐碎的例子:


public class Singleton
{
    private Singleton()
    {
        // Prevent outside instantiation
    }

    private static readonly Singleton _singleton = new Singleton();

    public static Singleton GetSingleton()
    {
        return _singleton;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 不是线程安全.两个线程可以同时调用,并可以创建两个单独的对象. (12认同)
  • 不,我认为你的评论很重要.鉴于单身人员应该提供一个 - 而且只有一个 - 实例,这里的竞争条件开启了交付多个人的可能性.使用静态字段初始化查看现在的版本.我认为这可以解决线程安全问题,如果我阅读[文档](https://msdn.microsoft.com/en-us/library/aa645758%28v=vs.71%29.aspx)和[此SO回答](http://stackoverflow.com/a/12159883/208990)正确. (8认同)
  • @Alagesan Palani,你确实是对的.我并不精通类级初始化的低级细节,但我认为我所做的更改解决了线程安全问题. (4认同)
  • 当然,我并不是说你错了.我正在向读者暗示线程安全性,以便他们必须小心处理它. (2认同)

Aar*_*ght 39

它是什么:在应用程序的生命周期中只有一个持久实例的类.请参见单例模式.

什么时候应该使用它:尽可能少.只有当你完全确定你需要它时.我不愿意说"从不",但通常有一个更好的选择,例如依赖注入或简单的静态类.

  • 我不确定静态类是否比单例更好...它真的取决于情况和语言. (16认同)
  • 我低估了这个答案,因为它没有给我任何关于何时使用它的信息."只有在你需要它的时候"并没有真正给我任何有关单身人士的信息. (9认同)
  • @Adkins:DI代表依赖注入,这是通过(通常)构造函数或公共属性传入任何类依赖关系的时候.单独的DI不能解决"距离"问题,但它通常与控制反转(IoC)容器一起实现,该容器知道如何自动初始化任何依赖关系.因此,如果您要创建Singleton来解决"X不知道如何查找/与Y对话"的问题,DI和IoC的组合可以解决与松散耦合相同的问题. (9认同)
  • 静态类的行为方式与单例不同,单例可以作为参数传递给方法,而静态类则不能. (4认同)
  • 与marcgg一起使用 - 我没有看到静态类作为单例的一个很好的替代品,因为你仍然有提供替代品的问题,例如在测试依赖于这个类的组件时.但我也看到了不同的用法,静态类通常用于独立于状态的独立实用程序函数,其中单例是实际的类实例,并且它通常存储状态.我完全同意使用DI,然后告诉您的DI容器您希望它只使用该类的单个实例. (4认同)

Mar*_* R. 24

另一种在c#中实现singleton的方法,我个人更喜欢这种方式,因为你可以将singeton类的实例作为属性而不是方法来访问.

public class Singleton
    {
        private static Singleton instance;

        private Singleton() { }

        public static Singleton Instance
        {
            get
            {
                if (instance == null)
                    instance = new Singleton();
                return instance;
            }
        }

        //instance methods
    }
Run Code Online (Sandbox Code Playgroud)

但是,据我所知,这两种方式都被认为是"正确的",所以这只是个人风格.

  • 不是线程安全.两个线程可以同时调用,并可以创建两个单独的对象. (11认同)

bry*_*val 10

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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我从dofactory.com上获取代码,没什么好看的但是我觉得这比Foo和Bar的例子还要好,还有来自Judith Bishop的关于C#3.0的图书设计模式有关于mac dock中活动应用的例子.

如果你查看代码,我们实际上是在for循环上构建新对象,所以创建新对象但重用实例,因为oldbalancer和newbalancer具有相同的实例,如何?由于函数GetLoadBalancer()使用静态关键字,尽管具有不同的服务器值是随机列表,但GetLoadBalancer()上的静态属于类型本身而不是特定对象.

此外,还有双重检查锁定在这里

if (_instance == null)
            {
                lock (syncLock)
                {
                    if (_instance == null)
Run Code Online (Sandbox Code Playgroud)

来自MSDN

lock关键字确保一个线程不进入代码的关键部分,而另一个线程处于临界区.如果另一个线程试图输入锁定的代码,它将等待,阻止,直到该对象被释放.

所以每次都会发出互斥锁,即使它不需要也不需要,所以我们进行空检查.

希望它有助于清除更多.

如果我的理解是指导错误的方式,请评论.


BFr*_*ree 6

Singleton(这与C#无关,它是一种OO设计模式)是您希望在整个应用程序中只允许创建一个类的一个实例.使用通常包括全球资源,虽然我会从个人经验中说,但它们往往是巨大痛苦的根源.


Tab*_*ool 5

虽然只能有一个单例的实例,但它与静态类不同.静态类只能包含静态方法,并且永远不能实例化,而单例实例的使用方式与任何其他对象相同.