ตัวสร้างแบบคงที่ถูกเรียกใน C # เมื่อใด


88

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

คำตอบ:


93

เมื่อมีการเข้าถึงชั้นเรียนเป็นครั้งแรก

ตัวสร้างแบบคงที่ (คู่มือการเขียนโปรแกรม C #)

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


6
น่าสนใจตรงที่มีข้อความระบุว่า "ก่อนสร้างอินสแตนซ์แรกหรือสมาชิกแบบคงที่จะถูกอ้างอิง" มีสิ่งที่คั่งค้างอยู่ที่นั่นเมื่อมีการเรียกใช้จริง
Tim Barrass

6
@TimB อายเนื่องจากข้อกำหนดอื่น ๆ ของข้อกำหนดปรากฎว่า "ก่อน" เป็น "ก่อน" จริง - ดูบทความของ Jon Skeet ที่อ้างถึงในคำตอบอื่น ๆ - stackoverflow.com/a/1437372/477420
Alexei Levenkov

A static constructor is used to initialize any static dataไม่ ดีกว่าที่จะใช้static initializerเพื่อเริ่มต้นสิ่งที่คงที่
Yousha Aleayoub

41

มันไม่ง่ายอย่างที่คุณคาดหวังแม้จะมีเอกสารที่ตรงไปตรงมา บทความของ Jon Skeet http://csharpindepth.com/Articles/General/Beforefieldinit.aspxจะกล่าวถึงคำถามนี้โดยละเอียด

สรุป:

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

โปรดทราบว่าตัวเริ่มต้นแบบคงที่ (หากไม่มีตัวสร้างแบบคงที่) รับประกันว่าจะดำเนินการได้ทุกเมื่อก่อนที่จะอ้างอิงไปยังฟิลด์เฉพาะเป็นครั้งแรก


บทความดังกล่าวอยู่ในเว็บไซต์ของ Jon Skeet: csharpindepth.com/Articles/General/Beforefieldinit.aspx
Sudhanshu Mishra

คำถามต่อไปนี้stackoverflow.com/questions/32525628/…แสดงให้เห็นถึงกรณีที่พฤติกรรม "ทันที" ค่อนข้างชัดเจน
Alexei Levenkov

1
ฉันเพิ่งเคยมีกรณีที่ตัวสร้างแบบคงที่ถูกเรียกใช้ก่อนที่เมธอดหลักของแอปพลิเคชันคอนโซลจะเริ่มดำเนินการด้วยซ้ำ!
HerpDerpington

19

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

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


2
เมื่อมันเกิดขึ้นจะไม่ "ขึ้นอยู่กับการนำไปใช้งาน" หากการนำไปใช้นั้นเป็นไปตามข้อกำหนด ECMA C #: "การดำเนินการของตัวสร้างแบบคงที่จะถูกทริกเกอร์โดยเหตุการณ์แรกต่อไปนี้ที่จะเกิดขึ้นภายในโดเมนแอปพลิเคชัน: [1] อินสแตนซ์ของ คลาสถูกสร้างขึ้น [2] สมาชิกสแตติกใด ๆ ของคลาสจะถูกอ้างอิง " (ตอนที่ 17.11 ecma-international.org/publications/standards/Ecma-334.htm )
LukeH

1
@Luke: "เวลาที่แน่นอนของการดำเนินการตัวสร้างแบบคงที่ขึ้นอยู่กับการนำไปใช้งาน" ondotnet.com/pub/a/dotnet/2003/07/07/staticxtor.html
Guffa

2
@Guffa: นั่นอาจเป็นการตีความของผู้เขียนบทความ แต่คุณจะไม่พบถ้อยคำนั้นในข้อกำหนด C # เวอร์ชัน Microsoft หรือ ECMA / ISO
LukeH

1

ในกรณีที่วิธีการแบบคงที่ถูกเรียกใช้จากคลาสแม่ตัวสร้างแบบคงที่จะไม่ถูกเรียกแม้ว่าจะมีการระบุไว้อย่างชัดเจน นี่คือตัวอย่าง b constructor ไม่ได้ถูกเรียกว่า b.methoda () ถูกเรียก

static void Main(string[] args)
{
    b.methoda();
}

class a
{
    public static void methoda()
    {
        //using initialized method data
    }
}

class b : a
{
    static b()
    {
        //some initialization
    }
}    

1

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

ตัวสร้างแบบคงที่เรียกว่าหลังจากตัวสร้างอินสแตนซ์?

ตัวสร้างแบบคงที่สามารถทำงานหลังจากตัวสร้างแบบไม่คงที่ นี่คือบั๊กของคอมไพเลอร์หรือไม่?

(คำตอบสำหรับฉันคือใส่ซิงเกิลตันในคลาสแยกต่างหากหรือเริ่มต้นข้อมูลแบบคงที่ด้วยตนเองในตัวสร้างอินสแตนซ์ก่อนที่จะต้องใช้)

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