ซิงเกิลตันใน C # คืออะไร


182

Singleton คืออะไรและควรใช้เมื่อใด


2
ซ้ำซ้อนที่เป็นไปได้: stackoverflow.com/questions/246710/…
ทำเครื่องหมาย Seemann

4
นอกจากนี้ซิงเกิลตันเป็นหนึ่งในรูปแบบการออกแบบที่ใช้กันอย่างแพร่หลายและถูกทารุณกรรมในการเขียนโปรแกรม OO
ChaosPandion

3
@ Fabiano: เพราะมันมีวิธีในการสร้างข้อต่อที่ไม่มีความหมาย (ฉันXจะคุยกับYอะไรได้แค่ทำYซิงเกิล!) ซึ่งจะนำไปสู่ปัญหาในการทดสอบ / การดีบักและรูปแบบการเขียนโปรแกรมตามขั้นตอน บางครั้ง Singletons มีความจำเป็น เวลาส่วนใหญ่ไม่ใช่
Aaronaught

3
นี่คือหนึ่งในคำถามสัมภาษณ์ทางโทรศัพท์มาตรฐานของฉัน คำตอบที่ถูกต้องคือ: ไม่เคย
jonnii

3
@jonnii เป็นสิ่งที่ดีมันช่วยเตือนนักพัฒนาที่คาดหวังว่าเจ้านายจะเป็นอย่างไร!
นายบอย

คำตอบ:


145

ซิงเกิลตันเป็นคลาสที่อนุญาตให้สร้างอินสแตนซ์ของตัวเองเพียงตัวเดียวเท่านั้นและให้การเข้าถึงอินสแตนซ์ที่ง่ายและสะดวก สมมติฐานเดียวเป็นรูปแบบในการพัฒนาซอฟต์แวร์

มี C # การดำเนินงานคือ"การดำเนินการตามรูปแบบซิงเกิลใน C #"รวมถึงบางคำแนะนำที่ดีเกี่ยวกับการ - ครอบคลุมมากที่สุดของสิ่งที่คุณจำเป็นต้องรู้หัวข้อความปลอดภัย

พูดตามตรงมันเป็นเรื่องยากมากที่คุณจะต้องใช้ซิงเกิลตัน - ในความคิดของฉันมันควรจะเป็นหนึ่งในสิ่งเหล่านั้นที่คุณควรระวังแม้ว่ามันจะไม่ได้ใช้บ่อยเกินไปก็ตาม


2
กวดวิชาที่ดี แต่อึศักดิ์สิทธิ์พวกเขาทำอะไรกับรหัสเยื้อง
Inspi

นี่คือการเชื่อมโยงโดยตรงมากขึ้นกับสิ่งที่ผมคิดว่าจะเป็นการดำเนินงานที่ดีเยี่ยมในปี 2020 นั่นคือ " การใช้ .NET 4 Lazy <T> ประเภท " Lazy<T> Classเช่นเดียวกับการเชื่อมโยงไปยังไมโครซอฟท์สำหรับหมอ
Chiramisu

52

คุณถามหา C # ตัวอย่างเล็กน้อย:


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

    private static readonly Singleton _singleton = new Singleton();

    public static Singleton GetSingleton()
    {
        return _singleton;
    }
}

14
ไม่ใช่เธรดที่ปลอดภัยเธรดสองตัวสามารถเรียกใช้เวลาเดียวกันและสามารถสร้างวัตถุแยกสองรายการ
Alagesan Palani

5
@Alagesan Palani แน่นอนคุณพูดถูก ฉันไม่เชี่ยวชาญในรายละเอียดในระดับต่ำของการกำหนดค่าเริ่มต้นระดับชั้นเรียน แต่ฉันคิดว่าการเปลี่ยนแปลงที่ฉันทำอยู่นั้นคำนึงถึงความปลอดภัยของเธรด
Chris Simmons

3
แน่นอนฉันไม่ได้ชี้ว่าคุณผิด ฉันให้คำแนะนำแก่ผู้อ่านเกี่ยวกับความปลอดภัยของเธรดเพื่อว่าพวกเขาจะระมัดระวังหากพวกเขาต้องจัดการกับมัน
Alagesan Palani

9
ไม่ฉันคิดว่าความคิดเห็นของคุณเป็นสิ่งสำคัญ เมื่อพิจารณาว่ามีการส่งมอบซิงเกิลตันเพียงครั้งเดียวและอินสแตนซ์เดียวสภาพการแข่งขันในที่นี้จะเปิดโอกาสให้ส่งมอบมากกว่าหนึ่งครั้ง ดูรุ่นตอนนี้ด้วยการเริ่มต้นสนามคงที่ ฉันเชื่อว่านี่จะช่วยแก้ปัญหาความปลอดภัยของเธรดถ้าฉันอ่านเอกสารและคำตอบนี้จึงถูกต้อง
Chris Simmons

1
@AlagesanPalani ฉันเห็นว่าคุณได้ระบุว่าคำตอบอื่น ๆ อีกมากมายไม่ปลอดภัยสำหรับเธรด คุณสนใจที่จะจัดหาโซลูชั่นที่ปลอดภัยสำหรับเธรดหรือไม่?
Bonez024

39

มันคืออะไร:คลาสที่มีเพียงหนึ่งอินสแตนซ์ที่คงอยู่ตลอดอายุการใช้งานของแอปพลิเคชัน ดูแบบซิงเกิล

เมื่อใดที่คุณควรใช้:น้อยที่สุด เฉพาะเมื่อคุณมั่นใจอย่างแน่นอนว่าคุณต้องการมัน ฉันลังเลที่จะพูดว่า "ไม่เคย" แต่โดยปกติจะมีทางเลือกที่ดีกว่าเช่นการพึ่งพาการฉีดหรือเพียงแค่ระดับคงที่


16
ฉันไม่แน่ใจว่าคลาสแบบสแตติกเป็นทางเลือกที่ดีกว่าแบบซิงเกิล ... ขึ้นอยู่กับสถานการณ์และภาษา
marcgg

5
คลาสสแตติกไม่ทำงานในลักษณะเดียวกับซิงเกิลซิงเกิลสามารถส่งผ่านไปยังเมธอดเป็นพารามิเตอร์ในขณะที่คลาสสแตติกไม่สามารถทำได้
TabbyCool

4
Aggree กับ marcgg - ฉันไม่เห็นคลาสแบบคงที่เป็นทางเลือกที่ดีสำหรับ singletons เนื่องจากคุณยังคงมีปัญหาในการจัดหาตัวแทนเช่นในระหว่างการทดสอบส่วนประกอบที่ขึ้นอยู่กับชั้นนี้ แต่ฉันก็เห็นการใช้ที่แตกต่างกันโดยทั่วไปคลาสแบบสแตติกจะถูกใช้สำหรับฟังก์ชันยูทิลิตี้อิสระที่ไม่ขึ้นอยู่กับสถานะโดยที่ singleton เป็นอินสแตนซ์ของคลาสจริง ฉันเห็นด้วยอย่างยิ่งที่จะใช้ DI แทนจากนั้นให้บอกคอนเทนเนอร์ DI ของคุณว่าคุณต้องการให้ใช้อินสแตนซ์เดียวของคลาสนั้น
Pete

9
ฉันลงคะแนนคำตอบนี้เพราะมันทำให้ฉันไม่มีข้อมูลเกี่ยวกับเวลาที่จะใช้มัน "เมื่อคุณต้องการเท่านั้น" ไม่ได้ให้ข้อมูลใด ๆ แก่ฉันเลยสำหรับคนที่ยังใหม่กับซิงเกิล
Sergio Tapia

9
@Adkins: DI ย่อมาจาก Dependency Injection ซึ่งเมื่อการอ้างอิงคลาสใด ๆ ถูกส่งผ่าน (โดยปกติ) คอนสตรัคหรือทรัพย์สินสาธารณะ DI เพียงอย่างเดียวไม่สามารถแก้ปัญหา "ระยะทาง" แต่โดยทั่วไปแล้วจะนำไปใช้พร้อมกับคอนเทนเนอร์ Inversion-of-Control (IoC) ที่รู้วิธีเริ่มต้นการพึ่งพาโดยอัตโนมัติ ดังนั้นหากคุณกำลังสร้างซิงเกิลตันเพื่อแก้ปัญหา "X ไม่ทราบวิธีค้นหา / พูดคุยกับ Y" การรวมกันของ DI และ IoC สามารถแก้ปัญหาเดียวกันได้ด้วยการเชื่อมต่อแบบหลวม
Aaronaught

27

อีกวิธีหนึ่งในการนำ singleton มาใช้ใน c # ฉันชอบวิธีนี้เป็นการส่วนตัวเพราะคุณสามารถเข้าถึงอินสแตนซ์ของคลาส 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
    }

แต่เท่าที่ฉันรู้ว่าทั้งสองวิธีได้รับการพิจารณาว่า 'ถูกต้อง' ดังนั้นมันจึงเป็นแค่เรื่องของรสนิยมส่วนตัว


11
ไม่ใช่เธรดที่ปลอดภัยเธรดสองตัวสามารถเรียกใช้เวลาเดียวกันและสามารถสร้างวัตถุแยกสองรายการ
Alagesan Palani

11
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 dock

ถ้าคุณดูโค้ดเรากำลังสร้างออบเจ็กต์ใหม่เพื่อลูปดังนั้นมันจะสร้างออบเจ็กต์ใหม่ แต่นำอินสแตนซ์กลับมาใช้ใหม่ซึ่งเป็นผลมาจากการที่โอเพ่นบาลานส์และนิวบาลานเซอร์มีอินสแตนซ์เดียวกัน เนื่องจากคำสำคัญคงที่ใช้ในฟังก์ชั่นGetLoadBalancer ()แม้จะมีค่าเซิร์ฟเวอร์ที่แตกต่างกันซึ่งเป็นรายการแบบสุ่มคงที่ในGetLoadBalancer ()เป็นประเภทของตัวเองมากกว่าวัตถุที่เฉพาะเจาะจง

นอกจากนี้ยังมีการตรวจสอบการล็อคซ้ำที่นี่

if (_instance == null)
            {
                lock (syncLock)
                {
                    if (_instance == null)

ตั้งแต่จาก MSDN

คีย์เวิร์ด lock ทำให้แน่ใจว่าเธรดหนึ่งไม่ได้ป้อนส่วนที่สำคัญของโค้ดในขณะที่เธรดอื่นอยู่ในส่วนที่สำคัญ หากเธรดอื่นพยายามป้อนรหัสที่ถูกล็อคมันจะรอบล็อกจนกว่าวัตถุจะถูกปล่อยออกมา

ดังนั้นจึงมีการออกการล็อกการยกเว้นซึ่งกันและกันทุกครั้งแม้ว่าจะไม่จำเป็นต้องใช้ซึ่งไม่จำเป็นดังนั้นเราจึงตรวจสอบ null

หวังว่ามันจะช่วยในการล้างข้อมูลเพิ่มเติม

และโปรดแสดงความคิดเห็นหากฉันเข้าใจว่าฉันกำลังกำกับวิธีที่ผิด


6

Singleton (และนี่ไม่ได้เชื่อมโยงกับ C # มันเป็นรูปแบบการออกแบบ OO) คือเมื่อคุณต้องการอนุญาตให้สร้างคลาสได้เพียงอินสแตนซ์เดียวทั่วทั้งแอปพลิเคชันของคุณ โดยทั่วไปแล้วการใช้งานจะรวมถึงแหล่งข้อมูลทั่วโลกถึงแม้ว่าฉันจะบอกว่าจากประสบการณ์ส่วนตัวพวกเขามักจะเป็นแหล่งของความเจ็บปวดที่ยิ่งใหญ่


5

ในขณะที่มีเพียงหนึ่งตัวอย่างของซิงเกิลเท่านั้นมันไม่เหมือนกับคลาสแบบสแตติก คลาสสแตติกสามารถมีเมธอดแบบสแตติกเท่านั้นและไม่สามารถอินสแตนซ์ได้ในขณะที่อินสแตนซ์ของซิงเกิลอาจถูกใช้ในลักษณะเดียวกับวัตถุอื่น ๆ


2

มันเป็นรูปแบบการออกแบบและไม่เฉพาะเจาะจงกับ c # เพิ่มเติมเกี่ยวกับเรื่องนี้ทั้งหมดผ่านทางอินเทอร์เน็ตและอื่น ๆ เช่นนี้บทความวิกิพีเดีย

ในวิศวกรรมซอฟต์แวร์รูปแบบซิงเกิลเป็นรูปแบบการออกแบบที่ใช้เพื่อ จำกัด การสร้างอินสแตนซ์ของคลาสให้เป็นหนึ่งวัตถุ สิ่งนี้มีประโยชน์เมื่อต้องการวัตถุหนึ่งชิ้นเพื่อประสานการทำงานข้ามระบบ บางครั้งแนวคิดถูกทำให้เป็นแนวไปยังระบบที่ทำงานได้อย่างมีประสิทธิภาพมากขึ้นเมื่อมีวัตถุเพียงวัตถุเดียวเท่านั้นหรือ จำกัด การสร้างอินสแตนซ์ให้กับวัตถุจำนวนหนึ่ง บางคนคิดว่าเป็นรูปแบบการต่อต้านโดยตัดสินว่ามีการใช้มากเกินไปแนะนำข้อ จำกัด ที่ไม่จำเป็นในสถานการณ์ที่ไม่จำเป็นต้องใช้อินสแตนซ์ของคลาสเพียงอย่างเดียว

คุณควรใช้มันหากคุณต้องการชั้นเรียนที่สามารถเปิดใช้งานได้เพียงครั้งเดียว


2

ฉันใช้เพื่อค้นหาข้อมูล โหลดหนึ่งครั้งจาก DB

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;
        }

    }

2

Singleton คืออะไร:
เป็นคลาสที่อนุญาตให้สร้างอินสแตนซ์ของตัวเองเพียงหนึ่งตัวและมักจะให้การเข้าถึงอินสแตนซ์นั้นง่าย

เมื่อใดที่คุณควรใช้:
ขึ้นอยู่กับสถานการณ์

หมายเหตุ: โปรดอย่าใช้กับการเชื่อมต่อ db สำหรับคำตอบโดยละเอียดโปรดดูคำตอบของ @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

ดูที่นี่สำหรับตัวอย่างโดยละเอียดเพิ่มเติมโดยใช้Lazy<T>


1

นี่คือความหมายของซิงเกิล: http://en.wikipedia.org/wiki/Singleton_pattern

ฉันไม่รู้ C # แต่จริงๆแล้วมันก็เหมือนกันในทุกภาษา

โดยทั่วไปคุณควรหลีกเลี่ยงซิงเกิลตันเมื่อเป็นไปได้ แต่ในบางสถานการณ์มันสะดวกมาก

ขออภัยภาษาอังกฤษของฉัน;)


ภาษาอังกฤษของคุณก็โอเค :)
FrenkyB

1

คลาส Singleton ใช้เพื่อสร้างอินสแตนซ์เดียวสำหรับโดเมนแอปพลิเคชันทั้งหมด

public class Singleton
{
    private static Singleton singletonInstance = CreateSingleton();

    private Singleton()
    {
    }

    private static Singleton CreateSingleton()
    {
        if (singletonInstance == null)
        {
            singletonInstance = new Singleton();
        }

        return singletonInstance;
    }

    public static Singleton Instance
    {
        get { return singletonInstance; }            
    }
}

ในบทความนี้มีการอธิบายถึงวิธีการที่เราสามารถสร้างคลาส singleton safe ที่ปลอดภัยโดยใช้ตัวแปร readonly และการใช้งานจริงในแอพพลิเคชัน


1

ฉันรู้ว่ามันสายเกินไปที่จะตอบคำถาม แต่ด้วยคุณสมบัติอัตโนมัติคุณสามารถทำสิ่งนี้ได้:

public static Singleton Instance { get; } = new Singleton();

อยู่ที่ไหนก็คือคุณระดับและสามารถที่จะผ่านในกรณีนี้อ่านได้อย่างเดียวคุณสมบัติSingletonInstance


0

EX คุณสามารถใช้ Singleton สำหรับข้อมูลทั่วโลกที่จำเป็นต้องถูกฉีด

ในกรณีของฉันฉันเก็บรายละเอียดผู้ใช้ที่บันทึกไว้ (ชื่อผู้ใช้สิทธิ์ ฯลฯ ) ใน Global Static Class และเมื่อฉันพยายามที่จะใช้การทดสอบหน่วยไม่มีทางที่ฉันสามารถฉีดการพึ่งพาในชั้นเรียนควบคุมได้ ดังนั้นฉันได้เปลี่ยนรูปแบบการเรียนแบบคงที่เป็นแบบซิงเกิล

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


0

เราจำเป็นต้องใช้รูปแบบการออกแบบซิงเกิลตันใน C # เมื่อเราต้องการให้แน่ใจว่าจะมีการสร้างอินสแตนซ์ของคลาสที่เฉพาะเจาะจงเพียงอันเดียวจากนั้นให้การเข้าถึงระดับโลกที่ง่ายต่ออินสแตนซ์นั้นสำหรับแอปพลิเคชันทั้งหมด

สถานการณ์แบบเรียลไทม์ที่คุณสามารถใช้รูปแบบการออกแบบซิงเกิล: Service Proxies: เนื่องจากเรารู้ว่าการเรียกใช้ Service API เป็นการดำเนินการที่กว้างขวางในแอปพลิเคชัน กระบวนการที่ใช้เวลาส่วนใหญ่คือการสร้างไคลเอ็นต์บริการเพื่อเรียกใช้บริการ API หากคุณสร้างบริการพร็อกซี่เป็นซิงเกิลตันมันจะปรับปรุงประสิทธิภาพของแอปพลิเคชันของคุณ

Facades: คุณสามารถสร้างการเชื่อมต่อฐานข้อมูลเป็น Singleton ซึ่งสามารถปรับปรุงประสิทธิภาพของแอปพลิเคชัน

บันทึก: ในแอปพลิเคชันการดำเนินการ I / O บนไฟล์เป็นการดำเนินการที่มีราคาแพง หากคุณสร้าง Logger เป็น Singleton มันจะปรับปรุงประสิทธิภาพของการดำเนินการ I / O

การแบ่งปันข้อมูล: หากคุณมีค่าคงที่หรือค่าการกำหนดค่าคุณสามารถเก็บค่าเหล่านี้ไว้ใน Singleton เพื่อให้ส่วนประกอบเหล่านี้สามารถอ่านได้โดยแอปพลิเคชัน

แคช: เรารู้ดึงข้อมูลจากฐานข้อมูลเป็นกระบวนการที่ใช้เวลานาน ในแอปพลิเคชันของคุณคุณสามารถแคชต้นแบบและการกำหนดค่าในหน่วยความจำซึ่งจะหลีกเลี่ยงการเรียก DB ในสถานการณ์เช่นนี้คลาส Singleton สามารถใช้เพื่อจัดการแคชด้วยการซิงโครไนซ์เธรดในลักษณะที่มีประสิทธิภาพซึ่งช่วยปรับปรุงประสิทธิภาพการทำงานของแอปพลิเคชันได้อย่างมาก

ข้อเสียของรูปแบบการออกแบบ Singleton ใน C # ข้อเสียของการใช้รูปแบบการออกแบบ Singleton ใน C # มีดังนี้:

การทดสอบหน่วยเป็นเรื่องยากมากเพราะจะแนะนำสถานะสากลให้กับแอปพลิเคชัน มันลดโอกาสในการขนานในโปรแกรมเนื่องจากการเข้าถึงอินสแตนซ์ซิงเกิลในสภาพแวดล้อมแบบมัลติเธรดคุณจำเป็นต้องซีเรียลไลซ์วัตถุโดยใช้การล็อก

ฉันได้รับสิ่งนี้จากบทความต่อไปนี้

https://dotnettutorials.net/lesson/singleton-design-pattern/


0

Thread Singleton Safe โดยไม่ต้องใช้ตัวล็อคและไม่มีการสร้างอินสแตนซ์

การใช้งานนี้มีตัวสร้างแบบคงที่ดังนั้นจึงดำเนินการเพียงครั้งเดียวต่อโดเมนแอปพลิเคชัน

public sealed class Singleton
{

    static Singleton(){}

    private Singleton(){}

    public static Singleton Instance { get; } = new Singleton();

}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.