Singleton by Jon Skeet ชี้แจง


214
public sealed class Singleton
{
    Singleton() {}

    public static Singleton Instance
    {
        get
        {
            return Nested.instance;
        }
    }

    class Nested
    {
        // Explicit static constructor to tell C# compiler
        // not to mark type as beforefieldinit
        static Nested() {}
        internal static readonly Singleton instance = new Singleton();
    }
}

ฉันต้องการนำรูปแบบซิงเกิลของ Jon Skeet มาใช้ในแอปพลิเคชันปัจจุบันของฉันใน C #

ฉันมีข้อสงสัยสองข้อเกี่ยวกับรหัส

  1. เป็นไปได้อย่างไรในการเข้าถึงคลาสภายนอกภายในคลาสที่ซ้อนกัน ฉันหมายถึง

    internal static readonly Singleton instance = new Singleton();

    สิ่งที่เรียกว่าการปิด?

  2. ฉันไม่สามารถเข้าใจความคิดเห็นนี้

    // Explicit static constructor to tell C# compiler
    // not to mark type as beforefieldinit

    ความคิดเห็นนี้แนะนำอะไรเรา


12
ฮ่าฮ่าฉันคิดว่าฉันพูดไปแล้วว่ามันน่าเป็นห่วงนิดหน่อย ... กลายเป็นจอห์นโนแลนคนอื่น
จอห์นแอนโทนีแดเนียลโนแลน

14
สองสิ่งได้รับการยอมรับอย่างกว้างขวาง: ดวงอาทิตย์ขึ้นจากทิศตะวันออกและ Jon Skeet นั้นถูกต้องเสมอ แต่ฉันยังไม่แน่ใจเกี่ยวกับอดีต: P
akhil_mittal

2
@ thepirat000 - หากเขาเป็นเพียงผู้มีส่วนร่วมใน SO / Meta ฉันอาจไม่เห็นด้วย แต่เขามีอิทธิพลมากพอในโลกแห่งการเขียนโปรแกรมจริงที่อาจเป็นเรื่องจริง - ฉันแน่ใจว่ามีคนสร้างมันขึ้นมา ณ จุดหนึ่ง .
รหัส Jockey

8
อนุกรมวิธานของคำถามนี้จะถูกกล่าวถึงในเมตา
BoltClock

คำตอบ:


359
  1. ไม่สิ่งนี้ไม่เกี่ยวกับการปิด คลาสที่ซ้อนกันมีการเข้าถึงสมาชิกส่วนตัวของคลาสนอกรวมถึงตัวสร้างส่วนตัวที่นี่

  2. อ่านของฉันบทความเกี่ยวกับ beforefieldinit คุณอาจจะหรืออาจไม่ต้องการคอนสตรัคเตอร์แบบคงที่ไม่มี op ซึ่งขึ้นอยู่กับความเกียจคร้านที่คุณต้องการ คุณควรทราบว่า. NET 4 เปลี่ยนซีแมนทิกส์การเริ่มต้นจริง ๆ แล้วค่อนข้างจะค่อนข้าง (ยังอยู่ในสเป็ค แต่ขี้เกียจกว่าก่อน)

คุณต้องการรูปแบบนี้จริงๆหรือ? คุณแน่ใจหรือว่าไม่สามารถออกไปกับ:

public sealed class Singleton
{
    private static readonly Singleton instance = new Singleton();
    public static Singleton Instance { get { return instance; } }

    static Singleton() {}
    private Singleton() {}
}

12
@Anindya: ไม่ไม่เป็นไร คุณอาจต้องการส่ง JetBrains ไปบ่น :) :)
Jon Skeet

2
@ JonSkeet ฉันเพิ่งหยิบยกข้อกังวลต่อ JetBrains เกี่ยวกับเรื่องนี้ (# RSRP-274373) มาดูกันว่าพวกเขาสามารถเกิดอะไรขึ้น :)
Anindya Chatterjee

3
@Moons: คุณทำไม่ได้ ซิงเกิลตันมีอายุการใช้งาน AppDomain
Jon Skeet

2
@JonSkeet มีเหตุผลอะไรที่จะไม่ใช้Lazy<T>เพื่อที่คุณไม่ต้องประกาศตัวสร้างแบบคงที่สำหรับผลBeforeFieldInitข้างเคียงที่วิเศษ?
Ed T

3
FieldBeforeInit คือ MahaBharataจากMicrosoft
Amit มาร์กอช

49

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

    private class Nested

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

ดังนั้นหากคุณไม่ต้องการให้รันไทม์เพื่อเริ่มต้นฟิลด์ 'เชิงรุก' ก่อนที่คุณจะใช้งานให้เพิ่มตัวสร้างสแตติก

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

นั่นนำมาสู่การโพสต์ของ Jon เกี่ยวกับซิงเกิลตันซึ่งเป็น IMO ซึ่งเป็นหัวข้อพื้นฐานของคำถามนี้ โอ้และความสงสัย :-)

ฉันต้องการจะชี้ให้เห็นว่าซิงเกิลที่ 3 ของเขาซึ่งเขาทำเครื่องหมายว่า 'ผิด' นั้นถูกต้องจริง ๆ (เพราะล็อคหมายถึงอุปสรรคหน่วยความจำโดยอัตโนมัติเมื่อออก ) มันควรจะเร็วกว่า singleton # 2 เมื่อคุณใช้อินสแตนซ์มากกว่าหนึ่งครั้ง (ซึ่งมากกว่าหรือน้อยกว่าหนึ่งจุด :-)) ดังนั้นหากคุณต้องการการนำซิงเกิลซิงเกิลขี้เกียจมาใช้ฉันควรจะทำเพราะเหตุผลง่ายๆที่ (1) มันชัดเจนสำหรับทุกคนที่อ่านโค้ดของคุณว่าเกิดอะไรขึ้นและ (2) คุณรู้ว่าจะเกิดอะไรขึ้น ด้วยข้อยกเว้น

ในกรณีที่คุณสงสัย: ฉันจะไม่ใช้ซิงเกิลตัน # 6 เพราะมันจะนำไปสู่การหยุดชะงักและพฤติกรรมที่ไม่คาดคิดพร้อมกับข้อยกเว้นได้อย่างง่ายดาย สำหรับรายละเอียดโปรดดู:โหมดล็อคของคนขี้เกียจโดยเฉพาะ ExecutionAndPublication


62
Regarding question (1): The answer from Jon is correct ...Jon Skeet ถูกต้องเสมอ ....
Noctis

72
คะแนนพิเศษสำหรับการพยายามตอบคำถามเกี่ยวกับ Jon Skeet ที่ Jon Skeet ได้ตอบไปแล้ว
valdetero

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