ฉันควรสร้าง destructor เมื่อใด


185

ตัวอย่างเช่น:

public class Person
{
    public Person()
    {
    }

    ~Person()
    {
    }
}

เมื่อใดที่ฉันควรสร้าง destructor ด้วยตนเอง คุณต้องการสร้าง destructor เมื่อใด


1
ภาษา C # เรียกว่า "destructors" เหล่านี้ แต่คนส่วนใหญ่เรียกพวกเขาว่า "finalizers" เนื่องจากเป็นชื่อ. NET และลดความสับสนกับ C + + destructors (ซึ่งแตกต่างกันมาก) วิธีใช้งาน IDisposable และ Finalizers: 3 Easy Rules
Stephen Cleary

5
เมื่อคุณรู้สึกบ้าระห่ำ
capdragon

32
ฉันคิดว่าคีย์บอร์ดของ TomTom ทำงานผิดปกติ แคปล็อคเปิดและปิดเป็นระยะ ๆ แปลก.
Jeff LaFay


ฉันลงเอยด้วยการใช้ destructor เพื่อช่วยในการดีบั๊กตามข้อเสนอแนะของ Greg Beech: stackoverflow.com/questions/3832911/…
Brian

คำตอบ:


237

UPDATE: คำถามนี้เป็นเรื่องของการบล็อกของฉันในเดือนพฤษภาคมปี 2015 ขอบคุณสำหรับคำถามที่ยอดเยี่ยม! ดูบล็อกเพื่อดูรายการเท็จที่คนทั่วไปเชื่อว่าเกี่ยวกับการสรุป

เมื่อใดที่ฉันควรสร้าง destructor ด้วยตนเอง

แทบจะไม่เคย.

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

ถ้าคุณทำ destructor ต้องระมัดระวังอย่างมากและเข้าใจวิธีการเก็บขยะทำงาน Destructors แปลกจริง ๆ :

  • พวกเขาไม่ทำงานบนเธรดของคุณ พวกเขาทำงานในหัวข้อของตัวเอง อย่าทำให้เกิดการหยุดชะงัก!
  • ข้อยกเว้นที่ไม่สามารถจัดการได้ที่ส่งมาจากผู้ทำลายล้างเป็นข่าวร้าย มันอยู่ในหัวข้อของตัวเอง; ใครจะไปจับมัน
  • destructor อาจถูกเรียกบนวัตถุหลังจากตัวสร้างเริ่มต้น แต่ก่อนที่ตัวสร้างเสร็จสิ้น destructor ที่เขียนอย่างถูกต้องจะไม่พึ่งพาค่าคงที่ที่กำหนดไว้ในตัวสร้าง
  • destructor สามารถ "คืนชีพ" วัตถุทำให้วัตถุที่ตายแล้วมีชีวิตอีกครั้ง มันแปลกจริงๆ อย่าทำมัน
  • destructor อาจไม่ทำงาน คุณไม่สามารถพึ่งพาวัตถุที่เคยถูกกำหนดให้ทำการสรุปได้ มันอาจจะเป็น แต่นั่นไม่ใช่การรับประกัน

เกือบจะไม่มีอะไรที่เป็นความจริงตามปกติเป็นความจริงในผู้ทำลายล้าง ระวังตัวด้วยจริงๆ การเขียน destructor ที่ถูกต้องนั้นยากมาก

คุณต้องการสร้าง destructor เมื่อใด

เมื่อทำการทดสอบส่วนหนึ่งของคอมไพเลอร์ที่จัดการกับ destructors ฉันไม่เคยต้องการที่จะทำในรหัสการผลิต ฉันไม่ค่อยเขียนวัตถุที่จัดการทรัพยากรที่ไม่มีการจัดการ


"destructor อาจถูกเรียกบนวัตถุหลังจากตัวสร้างเริ่มต้น แต่ก่อนที่ตัวสร้างเสร็จสิ้น" แต่ฉันสามารถพึ่งพาตัวเริ่มต้นของฟิลด์เพื่อเรียกใช้ใช่ไหม
กำหนดค่า

13
@configurator: ไม่ สมมติว่า initializer ฟิลด์ที่สามของวัตถุที่มี finalizer เรียกว่าเมธอดสแตติกซึ่งทำให้เกิดข้อยกเว้นจะถูกโยนทิ้ง ตัวกำหนดค่าเริ่มต้นของฟิลด์ที่สี่จะทำงานเมื่อใด ไม่เคย แต่วัตถุยังคงถูกจัดสรรและจะต้องเสร็จสิ้น Heck คุณไม่มีการรับประกันว่าเขตข้อมูลชนิด double ถูกเตรียมใช้งานอย่างสมบูรณ์เมื่อ dtor ทำงาน อาจมีการยกเลิกเธรดระหว่างการเขียน double และตอนนี้ finalizer ต้องจัดการกับ double-zero initialized half-zero
Eric Lippert

1
โพสต์ที่ยอดเยี่ยม แต่ควรพูดว่า "ควรจะสร้างขึ้นเมื่อคลาสของคุณถือวัตถุที่ไม่มีการจัดการที่มีราคาแพงหรือทำให้วัตถุที่ไม่มีการจัดการจำนวนมากอยู่" - ยกตัวอย่างเช่นฉันมีคลาสเมทริกซ์ใน C # ที่ใช้ภาษา C ++ คลาสเมทริกซ์ที่ต้องทำการยกของหนัก - ฉันทำเมทริกซ์มากมาย - "destructor" นั้นเหนือกว่า IDisposable ในกรณีนี้เพราะมันช่วยให้ด้านที่มีการจัดการและไม่มีการจัดการของบ้านดีขึ้น
Mark Mullin

1
pythonnet ใช้เตาเผาจะปล่อย GIL ใน CPython ไม่มีการจัดการ
denfromufa

3
สุดยอดบทความของ Eric อุปกรณ์ประกอบฉากสำหรับเรื่องนี้ -> "ความสนุกโบนัสพิเศษ: รันไทม์ใช้การสร้างรหัสที่ก้าวร้าวน้อยลงและการรวบรวมขยะที่ก้าวร้าวน้อยลงเมื่อเรียกใช้โปรแกรมในดีบักเกอร์เนื่องจากเป็นประสบการณ์การดีบักที่ไม่ดีในการมีวัตถุที่คุณกำลังดีบัก ตัวแปรที่อ้างอิงถึงออบเจ็กต์นั้นอยู่ในขอบเขตนั่นหมายความว่าหากคุณมีข้อผิดพลาดที่วัตถุจะถูกสรุปเร็วเกินไปคุณอาจไม่สามารถทำซ้ำบั๊กนั้นในตัวดีบักได้! "
Ken Palmer

17

มันเรียกว่า "finalizer" และโดยปกติคุณควรสร้างขึ้นมาสำหรับคลาสที่สถานะ (เช่น: ฟิลด์) รวมถึงทรัพยากรที่ไม่มีการจัดการ (เช่น: ตัวชี้เพื่อจัดการดึงข้อมูลผ่านการโทรแบบ p / เรียกใช้) อย่างไรก็ตามใน NET 2.0 และหลังจากนั้นมีจริงเป็นวิธีที่ดีกว่าที่จะจัดการกับการทำความสะอาดขึ้นของทรัพยากรที่ไม่มีการจัดการ: SafeHandle เมื่อพิจารณาถึงสิ่งนี้คุณไม่จำเป็นต้องเขียน finalizer อีกเลย


25
@ThomasEding - ใช่แล้ว C # ใช้ไวยากรณ์ destructor แต่มันจริงสร้างfinalizer อีกครั้ง
JDB ยังคงจดจำโมนิกา

@JDB: โครงสร้างภาษาศาสตร์เรียกว่า destructor ฉันไม่ชอบชื่อ แต่นั่นคือสิ่งที่เรียกว่า การกระทำการประกาศ destructor ทำให้คอมไพเลอร์สร้างวิธีการขั้นสุดท้ายซึ่งมีรหัสของ wrapper เล็กน้อยพร้อมกับสิ่งที่ปรากฏในร่างกายของ destructor
supercat

8

คุณไม่จำเป็นต้องใช้เว้นแต่ชั้นเรียนของคุณจะรักษาทรัพยากรที่ไม่มีการจัดการเช่นการจัดการไฟล์ Windows


5
จริงๆแล้วมันเรียกว่าผู้ทำลายล้าง
David Heffernan

2
ตอนนี้ฉันสับสน มันเป็น finalizer หรือ destructor หรือไม่?

4
ข้อมูลจำเพาะของ C # จะเรียกว่า destructor บางคนเห็นว่านี่เป็นความผิดพลาด stackoverflow.com/questions/1872700/…
Ani

2
@ThomasEding - ใช่แล้ว C # ใช้ไวยากรณ์ destructor แต่มันจริงสร้างfinalizer
JDB ยังคงจดจำโมนิก้า

2
ฉันรักการแสดงความคิดเห็นที่นี่ละครจริง :)
Benjol

4

มันเรียกว่า destructor / finalizer และมักจะสร้างขึ้นเมื่อใช้รูปแบบการจำหน่าย

เป็นโซลูชันสำรองเมื่อผู้ใช้ในชั้นเรียนของคุณลืมเรียกใช้ Dispose เพื่อให้แน่ใจว่า (ในที่สุด) ทรัพยากรของคุณได้รับการปล่อยตัวออกมา แต่คุณไม่มีการรับประกันใด ๆ เมื่อเรียกว่า destructor

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

แนวปฏิบัติที่ดีคือการไม่ใช้ตัวเลือกสุดท้ายโดยไม่ต้องให้ผู้ใช้ในชั้นเรียนมีความเป็นไปได้ในการกำจัดออบเจ็กต์ด้วยตนเองเพื่อปลดปล่อยทรัพยากรทันที


จริงๆแล้วมันไม่ได้เรียกว่า destructor ใน C # ด้วยเหตุผลที่ดี
TomTom

14
อันที่จริงมันเป็น ขอบคุณที่ให้คะแนนโหวตฉันเพราะคุณเข้าใจผิด ดูห้องสมุด MSDN เกี่ยวกับปัญหานี้โดยเฉพาะ: msdn.microsoft.com/en-us/library/66x5fx1b.aspx
ØyvindBråthen

1
@ TomTom ชื่ออย่างเป็นทางการคือ destructor
David Heffernan

จริง ๆ แล้วมันไม่ใช่วิธีทางเลือกมันช่วยให้ GC สามารถจัดการเมื่อวัตถุของคุณปราศจากทรัพยากรที่ไม่มีการจัดการการใช้ IDisposable ช่วยให้คุณจัดการด้วยตัวเอง
HasaniH

3

เมื่อคุณมีทรัพยากรที่ไม่มีการจัดการและคุณต้องทำให้แน่ใจว่าพวกเขาจะถูกล้างข้อมูลเมื่อวัตถุของคุณหายไป ตัวอย่างที่ดีคือวัตถุ COM หรือตัวจัดการไฟล์


2

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


1

Destructors จัดเตรียมวิธีการในการปลดปล่อยทรัพยากรที่ไม่ได้รับการจัดการที่ถูกห่อหุ้มในคลาสของคุณพวกมันจะถูกเรียกเมื่อ GC เข้าใกล้มันและพวกเขาเรียกวิธีการ Finalize ของคลาสพื้นฐานโดยปริยาย หากคุณใช้ทรัพยากรที่ไม่มีการจัดการจำนวนมากจะเป็นการดีกว่าที่จะให้วิธีการที่ชัดเจนในการปลดปล่อยทรัพยากรเหล่านั้นผ่านอินเทอร์เฟซ IDisposable ดูคู่มือการเขียนโปรแกรม C #: http://msdn.microsoft.com/en-us/library/66x5fx1b.aspx

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