try {
// Do stuff
}
catch (Exception e) {
throw;
}
finally {
// Clean up
}
ในบล็อกด้านบนบล็อกสุดท้ายเรียกเมื่อใด ก่อนโยนอีหรือสุดท้ายเรียกแล้วจับ?
try {
// Do stuff
}
catch (Exception e) {
throw;
}
finally {
// Clean up
}
ในบล็อกด้านบนบล็อกสุดท้ายเรียกเมื่อใด ก่อนโยนอีหรือสุดท้ายเรียกแล้วจับ?
คำตอบ:
มันจะถูกเรียกหลังจาก e ถูกโยนใหม่ (เช่นหลังจากดำเนินการจับบล็อก)
การแก้ไขสิ่งนี้ในอีก 7 ปีต่อมาสิ่งสำคัญประการหนึ่งก็คือหากeบล็อก try / catch ไม่ติดขึ้นจาก call stack หรือจัดการโดยตัวจัดการข้อยกเว้นส่วนกลางfinallyบล็อกอาจไม่ดำเนินการเลย
finallyจะไม่ทำงานถ้ายกเว้นโยนในก่อนหน้านี้catchไม่เคยถูกจับในด้านนอกtry- catchบล็อก!
ทำไมไม่ลอง:
outer try
inner try
inner catch
inner finally
outer catch
outer finally
ด้วยรหัส (จัดรูปแบบสำหรับพื้นที่แนวตั้ง):
static void Main() {
try {
Console.WriteLine("outer try");
DoIt();
} catch {
Console.WriteLine("outer catch");
// swallow
} finally {
Console.WriteLine("outer finally");
}
}
static void DoIt() {
try {
Console.WriteLine("inner try");
int i = 0;
Console.WriteLine(12 / i); // oops
} catch (Exception e) {
Console.WriteLine("inner catch");
throw e; // or "throw", or "throw anything"
} finally {
Console.WriteLine("inner finally");
}
}
outer try inner try inner catch Unhandled Exception: System.DivideByZeroException...
หลังจากอ่านคำตอบทั้งหมดที่นี่ดูเหมือนว่าคำตอบสุดท้ายจะขึ้นอยู่กับ :
หากคุณโยนข้อยกเว้นซ้ำภายในบล็อก catch และข้อยกเว้นนั้นติดอยู่ในบล็อก catch อื่นทุกอย่างจะดำเนินการตามเอกสารประกอบ
อย่างไรก็ตามหากไม่สามารถจัดการข้อยกเว้นการโยนซ้ำได้สุดท้ายก็จะไม่ดำเนินการ
ฉันทดสอบตัวอย่างโค้ดนี้ใน VS2010 w / C # 4.0
static void Main()
{
Console.WriteLine("Example 1: re-throw inside of another try block:");
try
{
Console.WriteLine("--outer try");
try
{
Console.WriteLine("----inner try");
throw new Exception();
}
catch
{
Console.WriteLine("----inner catch");
throw;
}
finally
{
Console.WriteLine("----inner finally");
}
}
catch
{
Console.WriteLine("--outer catch");
// swallow
}
finally
{
Console.WriteLine("--outer finally");
}
Console.WriteLine("Huzzah!");
Console.WriteLine();
Console.WriteLine("Example 2: re-throw outside of another try block:");
try
{
Console.WriteLine("--try");
throw new Exception();
}
catch
{
Console.WriteLine("--catch");
throw;
}
finally
{
Console.WriteLine("--finally");
}
Console.ReadLine();
}
นี่คือผลลัพธ์:
ตัวอย่างที่ 1: โยนเข้าไปในบล็อกลองอีกครั้ง: - เรา
เตอร์ลอง
---- ลอง
ด้านใน
---- จับด้านใน ---- ด้านในในที่สุด - เรา
เตอร์จับ - เรา
เตอร์ในที่สุด
Huzzah!ตัวอย่างที่ 2: โยนซ้ำนอกบล็อกลองอื่น:
--try
--catchUnhandled Exception: System.Exception: Exception of type 'System.Exception' ถูกโยนทิ้ง
ที่ ConsoleApplication1.Program.Main () ใน C: \ local source \ ConsoleApplication1 \ Program.cs: บรรทัดที่ 53
ตัวอย่างของคุณจะทำงานเหมือนกับรหัสนี้:
try {
try {
// Do stuff
} catch(Exception e) {
throw e;
}
} finally {
// Clean up
}
ในฐานะที่เป็นหมายเหตุด้านข้างถ้าคุณหมายถึงจริงๆthrow e;(นั่นคือโยนข้อยกเว้นเดียวกันกับที่คุณเพิ่งจับได้) จะดีกว่ามากที่จะทำthrow;เพราะจะรักษาสแต็กติดตามเดิมแทนที่จะสร้างใหม่
finallyบล็อกในความเป็นจริงจะทำงานหลังจากที่catchบล็อก (แม้ว่าการป้องกันการจับ rethrows ข้อยกเว้น) ซึ่งเป็นสิ่งที่ตัวอย่างข้อมูลของฉันพยายามที่จะแสดงให้เห็นถึง
tryบล็อกคำตอบของฉันมี "ลองจับ" ฉันพยายามอธิบายพฤติกรรมของโครงสร้าง 3 ส่วนโดยใช้โครงสร้าง 2 ส่วนสองส่วน ฉันไม่เห็นสัญญาณของtryบล็อกที่สองในคำถามเดิมดังนั้นฉันไม่เข้าใจว่าคุณได้รับสิ่งนั้นมาจากไหน
หากมีข้อยกเว้นที่ไม่สามารถจัดการได้ภายในบล็อกตัวจัดการการจับบล็อกจะถูกเรียกว่าเป็นศูนย์ครั้งในที่สุด
static void Main(string[] args)
{
try
{
Console.WriteLine("in the try");
int d = 0;
int k = 0 / d;
}
catch (Exception e)
{
Console.WriteLine("in the catch");
throw;
}
finally
{
Console.WriteLine("In the finally");
}
}
เอาท์พุต:
C: \ users \ administrator \ documents \ TestExceptionNesting \ bin \ Release> TestExceptionNesting.exe
ในการลอง
ในการจับ
Unhandled Exception: System.DivideByZeroException: พยายามหารด้วยศูนย์ ที่ TestExceptionNesting.Program.Main (String [] args) ใน C: \ users \ administrator \ documents \ TestExceptionNesting \ TestExceptionNesting.cs: บรรทัด 22
C: \ users \ administrator \ documents \ TestExceptionNesting \ bin \ release>
วันนี้ฉันถูกถามคำถามนี้ในการสัมภาษณ์และผู้สัมภาษณ์ก็ยังคงกลับไป "แน่ใจหรือว่าสุดท้ายจะไม่ถูกเรียก" ฉันไม่แน่ใจว่ามันหมายถึงคำถามหลอกหรือผู้สัมภาษณ์มีอย่างอื่นอยู่ในใจและเขียนรหัสผิดเพื่อให้ฉันแก้ไขข้อบกพร่องดังนั้นฉันจึงกลับบ้านและลองใช้ (สร้างและเรียกใช้ไม่มีการโต้ตอบดีบักเกอร์) เพียงเพื่อตั้งสติ พักผ่อน.
วิธีง่ายๆในการบอกก็คือการดีบักโค้ดของคุณและสังเกตว่าเมื่อใดที่ถูกเรียกในที่สุด
การทดสอบด้วยแอปพลิเคชัน C # Console ในที่สุดก็มีการเรียกใช้โค้ดหลังจากเกิดข้อยกเว้น: มี "กล่องโต้ตอบข้อผิดพลาดของแอปพลิเคชัน" อยู่และหลังจากที่คุณเลือกตัวเลือก "ปิดโปรแกรม" บล็อกในที่สุดก็ถูกดำเนินการในหน้าต่างคอนโซลนั้น แต่การกำหนดจุดแตกหักภายในบล็อกโค้ดในที่สุดฉันก็ไม่สามารถตีมันได้ ดีบักเกอร์หยุดที่คำสั่งโยน นี่คือรหัสทดสอบของฉัน:
class Program
{
static void Main(string[] args)
{
string msg;
Console.WriteLine(string.Format("GetRandomNuber returned: {0}{1}", GetRandomNumber(out msg), msg) == "" ? "" : "An error has occurred: " + msg);
}
static int GetRandomNumber(out string errorMessage)
{
int result = 0;
try
{
errorMessage = "";
int test = 0;
result = 3/test;
return result;
}
catch (Exception ex)
{
errorMessage = ex.Message;
throw ex;
}
finally
{
Console.WriteLine("finally block!");
}
}
}
การดีบักใน VS2010 - .NET Framework 4.0