เหตุใดจึงต้องลองใช้ {} ในที่สุด {} ด้วยบล็อกลองว่าง


239

ฉันสังเกตเห็นในSystem.Threading.TimerBase.Dispose()วิธีการมีtry{} finally{}บล็อก แต่try{}ว่างเปล่า

มีค่าใด ๆ ในการใช้try{} finally{}กับเปล่าtryหรือไม่?

http://labs.developerfusion.co.uk/SourceViewer/browse.aspx?assembly=SSCLI&namespace=System.Threading&type=TimerBase

[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
internal bool Dispose(WaitHandle notifyObject)
{
    bool status = false;
    bool bLockTaken = false;
    RuntimeHelpers.PrepareConstrainedRegions();
    try {
    }
    finally {
        do {
            if (Interlocked.CompareExchange(ref m_lock, 1, 0) == 0) {
                bLockTaken = true;
                try {
                    status = DeleteTimerNative(notifyObject.SafeWaitHandle);
                }
                finally {
                    m_lock = 0;
                }
            }
            Thread.SpinWait(1);
            // yield to processor
        }
        while (!bLockTaken);
        GC.SuppressFinalize(this);
    }

    return status;
}

System.Diagnostics
ประมวลผล

คำตอบ:


171

จากhttp://blog.somecreativity.com/2008/04/10/the-empty-try-block-mystery/ :

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


6
ทำไมไม่ใช้msdn.microsoft.com/en-us/library/… ?
Rob Fonseca-Ensor

15
เนื่องจากยังไม่มีให้บริการจนถึง. NET 2.0
Hans Passant

6
@ RobFonseca-Ensor: เนื่องจากThread.BeginCriticalRegion()ไม่ได้ป้องกันเธรดจากการถูกยกเลิกแทนที่จะบอกรันไทม์ว่าหากเธรดถูกยกเลิกสถานะโกลบอลจะเสียหายและแอปโดเมนทั้งหมดขึ้นอยู่กับการฆ่าด้วยความเมตตา
kkm

9
@HansPassant: BeginCriticalSection()จริงๆไม่ได้มีใน .NET 1.x แต่มีสาเหตุและไม่มีผลกระทบที่คุณอ้างถึงคำพูดเพราะ ในความเป็นจริงใน. NET 1.x แม้กระทั่งfinallyบล็อกอาจถูกขัดจังหวะโดยการยกเลิกเธรด กลไกเหล่านี้มีจุดประสงค์ที่แตกต่าง: ทำงานในการfinallyป้องกันการยกเลิกมิดเวย์ในรหัสในขณะที่BeginCriticalSection()ประกาศเฉพาะรันไทม์ที่รัฐทั่วโลกตกอยู่ในความเสี่ยง
kkm

หากนักพัฒนามีเวลาสักครู่ (จริง) ในที่สุดการทำแท้งจะสำเร็จหรือไม่หรือจะยกเลิกเทคนิคอย่างไม่มีกำหนด?
Max Young

64

นี่คือเพื่อป้องกันการThread.Abortขัดจังหวะกระบวนการ เอกสารสำหรับวิธีนี้บอกว่า:

ในที่สุดบล็อกที่ไม่ได้ดำเนินการจะถูกดำเนินการก่อนที่เธรดจะถูกยกเลิก

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

try {
    ...
}
finally {
    if(obj != null)
        ((IDisposable)obj).Dispose();
}

ใน. NET 1.x มีโอกาสที่finallyบล็อกจะถูกยกเลิก พฤติกรรมนี้มีการเปลี่ยนแปลงใน. NET 2.0

ยิ่งไปกว่านั้นtryบล็อกว่างเปล่าจะไม่ถูกปรับแต่งโดยคอมไพเลอร์


ขอบคุณสำหรับข้อมูลเชิงลึกเกี่ยวกับการใช้บล็อก
สเตฟาน

@ ทันใดนั้นฉันเข้าใจว่าการใช้เป็นแนวปฏิบัติที่ดีที่สุด แต่เพื่อวัตถุประสงค์ในการเยาะเย้ยบางครั้งจำเป็นต้องมีคลาส wrapper และวัตถุที่ใช้แล้วทิ้งจะกลายเป็นตัวแปรคลาสส่วนตัว หากเราทำให้เสื้อคลุมนี้ใช้แล้วทิ้ง GC จะไม่จัดการการทิ้งตัวแปรคลาสส่วนตัวโดยอัตโนมัติหรือไม่?
Ozkan

@Ozkan GC ไม่จำหน่ายสิ่งใดโดยอัตโนมัติ คุณจะต้องใช้ finalizer Dispose(false);โดยทั่วไปเรียก docs.microsoft.com/en-us/dotnet/standard/garbage-collection/…
Thorarin

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