จะพยายาม / ในที่สุด (โดยไม่มีการจับ) ฟองข้อยกเว้นหรือไม่?


116

ฉันเกือบจะคิดบวกว่าคำตอบคือใช่ หากฉันใช้การบล็อกลองในที่สุด แต่ไม่ได้ใช้บล็อก Catch ข้อยกเว้นใด ๆ จะเกิดฟอง แก้ไข?

มีความคิดเกี่ยวกับการปฏิบัติโดยทั่วไปหรือไม่?

เซท

คำตอบ:


131

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


13
@ เดวิด: คุณไม่สามารถกลับมาจากบล็อกใน C # ได้ในที่สุด
Jon Skeet

3
เอกสาร msdnยังยืนยันคำตอบนี้อีกด้วย
บรอดแบนด์

60

มีความคิดเกี่ยวกับการปฏิบัติโดยทั่วไปหรือไม่?

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

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

ตัวอย่างเช่นฉันมักจะเห็นสิ่งนี้:

DisableAccessToTheResource();
try
{
    DoSomethingToTheResource();
}
finally
{
    EnableAccessToTheResource();
}

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

ขั้นแรกการเข้าถึงทรัพยากรอาจถูกปิดใช้งานโดยผู้โทร ในกรณีนี้รหัสนี้จะเปิดใช้งานอีกครั้งซึ่งอาจเกิดขึ้นก่อนเวลาอันควร

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

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

ฉันมักจะเขียนโค้ดแบบนี้โดยไม่ใช้บล็อค try-final:

bool wasDisabled = IsAccessDisabled();
if (!wasDisabled)
    DisableAccessToTheResource();
DoSomethingToTheResource();
if (!wasDisabled)
    EnableAccessToTheResource();

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

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

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


7
ยังมีตัวอย่างเพิ่มเติมว่าเรายังไม่ได้ร่วมงานกันในฐานะอุตสาหกรรมเมื่อต้องจัดการข้อผิดพลาด ไม่ใช่ว่าฉันมีอะไรจะแนะนำได้ดีไปกว่าข้อยกเว้น แต่ฉันหวังว่าอนาคตจะมีบางสิ่งที่น่าจะนำไปสู่แนวทางการดำเนินการที่ถูกต้องและดำเนินการได้อย่างง่ายดายพอสมควร
Jon Skeet

ใน vb.net เป็นไปได้ที่โค้ดในบล็อกสุดท้ายจะทราบว่ามีข้อยกเว้นใดที่รอดำเนินการอยู่ หากมีใครตั้งค่าลำดับชั้นของข้อยกเว้นเพื่อแยกความแตกต่างว่า "ไม่ได้ทำ; รัฐเป็นอย่างอื่นไม่เป็นไร" จาก "สถานะเสีย" อาจมีการบล็อกในที่สุดก็ต่อเมื่อข้อยกเว้นที่รอดำเนินการไม่ใช่หนึ่งในข้อยกเว้นที่ไม่ดี ฉันต้องการให้กิจวัตรการกำจัด / การล้างข้อมูลจับข้อยกเว้นและโยน DisposerFailedException (ซึ่งอยู่ในหมวดหมู่ "ไม่ดี" และรวมข้อยกเว้นเดิมไว้เป็น InnerException) ฉันต้องการเห็นอินเทอร์เฟซ iDisposableEx มาตรฐานพร้อม Dispose (Ex as Exception) เพื่ออำนวยความสะดวก
supercat

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

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

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