ทำไมใช้ใน C # ในที่สุด?


189

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


3
คุณหมายถึงอะไรโดยปล่อยให้มันไม่เปิดเผย?
Ramesh

5
และคุณหมายถึงอะไรโดย "(เกือบ)"?
Beska

49
หากคุณดึงสายไฟออกในขณะที่เครื่องกำลังดำเนินการลองส่วนคำสั่งในที่สุดจะไม่ถูกเรียก
Dour High Arch

5
ฮ่า ๆ ใช่ว่าเป็นเรื่องจริง แต่คุณไม่สามารถรหัสสำหรับที่คุณสามารถ?
Ed S.

2
@Ed: ใช้ธุรกรรม ส่วนคำสั่งลองของคุณต้องทำการเปลี่ยนแปลงชั่วคราวหรือในหน่วยความจำบางประเภทซึ่งสามารถคงอยู่ในการเปลี่ยนแปลงอะตอมเดียวในประโยคสุดท้าย มันไม่ค่อยง่ายและอาจต้องใช้ฮาร์ดแวร์พิเศษ
Dour High Arch

คำตอบ:


405

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

ตอนนี้ฉันเดาคำถามของคุณว่าทำไมคุณควรทำสิ่งนี้:

try
{
    doSomething();
}
catch
{
    catchSomething();
}
finally
{
    alwaysDoThis();
}

เมื่อคุณสามารถทำสิ่งนี้:

try
{
    doSomething();
}
catch
{
    catchSomething();
}

alwaysDoThis();

คำตอบคือหลาย ๆ ครั้งที่โค้ดในคำสั่ง catch ของคุณจะทำการ rethrow ข้อยกเว้นหรือแยกออกจากฟังก์ชั่นปัจจุบัน ด้วยรหัสหลัง "alwaysDoThis ();" การโทรจะไม่ดำเนินการหากรหัสภายในคำสั่ง catch ส่งคืนหรือส่งข้อยกเว้นใหม่


3
อืมมม คล้ายกันมากกับสิ่งที่ฉันพูด แต่ชัดเจนและแม่นยำยิ่งขึ้น +1 แน่นอน
Beska

46
สิ่งนี้ใช้กับ "ส่งคืน" ภายในบล็อกลอง {} ด้วยเช่นกัน
ลูคัส

4
ในความเป็นจริงมันใช้แม้จะไม่มีการจับ {} บล็อก (แค่ลอง / ที่สุดให้ข้อยกเว้นฟองขึ้นไป)
ลูคัส

ดีกว่าของฉันแล้วทำงานและไม่ต้องการใช้เวลาสิบนาทีในการตอบคำถามโดยละเอียด +1
Matt Briggs

2
ใช่นี่คือสิ่งที่ฉันมีอยู่ในใจ: D ตอนนี้ฉันเข้าใจแล้ว
Rodrigo

62

ข้อได้เปรียบส่วนใหญ่ของการลองใช้ก็ชี้ให้เห็นแล้ว แต่ฉันคิดว่าฉันจะเพิ่มสิ่งนี้:

try
{
    // Code here that might throw an exception...

    if (arbitraryCondition)
    {
        return true;
    }

    // Code here that might throw an exception...
}
finally
{
    // Code here gets executed regardless of whether "return true;" was called within the try block (i.e. regardless of the value of arbitraryCondition).
}

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


2
นี่คือเหตุผลเดียวที่ฉันใช้ในที่สุด
Christopher Townsend

12

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

 SqlConnection myConn = new SqlConnection("Connectionstring");
        try
        {
            myConn.Open();
            //make na DB Request                
        }
        catch (Exception DBException)
        {
            //do somehting with exception
        }
        finally
        {
           myConn.Close();
           myConn.Dispose();
        }

หากคุณไม่ต้องการรับข้อผิดพลาดให้ใช้

 using (SqlConnection myConn = new SqlConnection("Connectionstring"))
        {
            myConn.Open();
            //make na DB Request
            myConn.Close();
        }

และวัตถุการเชื่อมต่อจะถูกกำจัดโดยอัตโนมัติหากมีข้อผิดพลาด แต่คุณไม่ได้จับข้อผิดพลาด


2
เลิกใช้ () จะปิด () การเชื่อมต่อโดยไม่จำเป็นต้องโทรหาทั้งคู่ ปิด () ไม่ได้ Dipose () คุณสามารถเปิดการเชื่อมต่อได้อีกครั้ง
ลูคัส

ดีมากขอบคุณที่พูดถึงการใช้ ฉันจะต้องตอบมิฉะนั้น
Dan Rosenstark


7

ในที่สุดงบสามารถดำเนินการได้แม้หลังจากกลับมา

private int myfun()
{
    int a = 100; //any number
    int b = 0;
    try
    {
        a = (5 / b);
        return a;
    }
    catch (Exception ex)
    {
        Response.Write(ex.Message);
        return a;
    }

 //   Response.Write("Statement after return before finally");  -->this will give error "Syntax error, 'try' expected"
    finally
    {
      Response.Write("Statement after return in finally"); // --> This will execute , even after having return code above
    } 

    Response.Write("Statement after return after finally");  // -->Unreachable code
}

7

finallyในขณะที่:

try {
  // do something risky
} catch (Exception ex) {
  // handle an exception
} finally {
  // do any required cleanup
}

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

ที่ทำให้มันสมบูรณ์แบบสำหรับสิ่งต่าง ๆ เช่นการปล่อยทรัพยากรการเชื่อมต่อฐานข้อมูลจัดการไฟล์ ฯลฯ


3
ตัวอย่างทั้งหมดเหล่านี้มักจะให้บริการที่ดีกว่าด้วยบล็อกที่ใช้ แต่นั่นไม่ได้เบี่ยงเบนความสนใจของคุณ
Joel Coehoorn

4

ฉันจะอธิบายการใช้งานในที่สุดพร้อมกับข้อยกเว้นตัวอ่านไฟล์ตัวอย่าง

  • โดยไม่ต้องใช้ในที่สุด
try{

  StreamReader strReader = new StreamReader(@"C:\Ariven\Project\Data.txt");
  Console.WriteLine(strReader.ReadeToEnd());
  StreamReader.Close();
}
catch (Exception ex)
{
  Console.WriteLine(ex.Message);
}

ในตัวอย่างด้านบนหากไฟล์ที่ชื่อว่าData.txtหายไปข้อยกเว้นจะถูกโยนทิ้งและจะได้รับการจัดการ แต่คำสั่งที่เรียกว่าStreamReader.Close();จะไม่ถูกเรียกใช้งาน
เนื่องจากทรัพยากรนี้ที่เกี่ยวข้องกับผู้อ่านไม่เคยถูกปล่อยออกมา

  • เพื่อแก้ปัญหาข้างต้นเราใช้ในที่สุด
StreamReader strReader = null;
try{
    strReader = new StreamReader(@"C:\Ariven\Project\Data.txt");
    Console.WriteLine(strReader.ReadeToEnd());
}
catch (Exception ex){
    Console.WriteLine(ex.Message);
}
finally{
    if (strReader != null){
        StreamReader.Close();
    }
}

Happy Coding :)

หมายเหตุ: "@" ใช้เพื่อสร้างสตริงverbatimเพื่อหลีกเลี่ยงข้อผิดพลาดของ "escape escape ที่ไม่รู้จัก" สัญลักษณ์ @ หมายถึงการอ่านสตริงนั้นอย่างแท้จริงและไม่ตีความอักขระควบคุมเป็นอย่างอื่น


2

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


2

บางครั้งคุณไม่ต้องการจัดการข้อยกเว้น (ไม่มี catch block) แต่คุณต้องการให้โค้ดการล้างข้อมูลดำเนินการ

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

try
{
    // exception (or not)
}
finally
{
    // clean up always
}

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

2

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


1

อ่า ... ฉันคิดว่าฉันเห็นสิ่งที่คุณพูด! เอาฉันสักครู่ ... คุณกำลังสงสัยว่า "ทำไมวางไว้ในบล็อกในที่สุดแทนที่จะเป็นบล็อกหลังจากนั้นในที่สุดและอยู่นอกการลองจับในที่สุด"

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


1

โฟลว์ควบคุมของบล็อกสุดท้ายคือหลังจากลองหรือจับบล็อก

[1. First Code]
[2. Try]
[3. Catch]
[4. Finally]
[5. After Code]

ด้วยข้อยกเว้น 1> 2> 3> 4> 5 ถ้า 3 มีคำสั่ง Return 1> 2> 3> 4

โดยไม่มีข้อยกเว้น 1> 2> 4> 5 ถ้า 2 มีคำสั่ง return 1> 2> 4


0

ตามที่ระบุไว้ในเอกสาร :

การใช้ catch และสุดท้ายร่วมกันคือการได้รับและใช้ทรัพยากรใน try block จัดการกับสถานการณ์พิเศษใน catch block และปล่อยทรัพยากรในบล็อกสุดท้าย

นอกจากนี้ยังควรอ่านสิ่งนี้ซึ่งระบุ:

เมื่อพบประโยค catch ที่ตรงกันระบบจะเตรียมการถ่ายโอนการควบคุมไปยังคำสั่งแรกของประโยค catch ก่อนที่จะเริ่มการทำงานของ catch clause จะเริ่มขึ้นระบบจะดำเนินการตามคำสั่งในที่สุดประโยคใด ๆ ที่เกี่ยวข้องกับคำสั่ง try จะซ้อนกันมากกว่าคำสั่ง catch

ดังนั้นจึงเป็นที่ชัดเจนว่ารหัสที่อยู่ในส่วนfinallyคำสั่งจะถูกดำเนินการแม้ว่าcatchข้อก่อนหน้านี้จะมีreturnคำสั่ง

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