Dispose ยังคงถูกเรียกเมื่อมีข้อยกเว้นอยู่ในคำสั่ง use?


105

ในตัวอย่างด้านล่างการเชื่อมต่อจะปิดและกำจัดเมื่อมีข้อยกเว้นเกิดขึ้นหากอยู่ในusingคำสั่ง?

using (var conn = new SqlConnection("..."))
{
    conn.Open();
    // stuff happens here and exception is thrown...
}

ฉันรู้ว่ารหัสด้านล่างนี้จะทำให้แน่ใจว่าได้ แต่ฉันอยากรู้ว่าการใช้คำสั่งทำอย่างไร

var conn;
try
{
    conn = new SqlConnection("...");
    conn.Open();
    // stuff happens here and exception is thrown...
}
// catch it or let it bubble up
finally
{
    conn.Dispose();
}

ที่เกี่ยวข้อง:

อะไรคือวิธีที่เหมาะสมในการตรวจสอบให้แน่ใจว่าการเชื่อมต่อ SQL ถูกปิดเมื่อมีข้อยกเว้นเกิดขึ้น?

คำตอบ:


113

ใช่usingห่อรหัสของคุณในการลอง / ปิดกั้นในที่สุดซึ่งfinallyส่วนจะเรียกDispose()ถ้ามีอยู่ อย่างไรก็ตามจะไม่โทรClose()โดยตรงเนื่องจากตรวจสอบเฉพาะIDisposableอินเทอร์เฟซที่กำลังใช้งานอยู่และด้วยเหตุนี้Dispose()วิธีการ

ดูสิ่งนี้ด้วย:


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

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

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

20

นี่คือวิธีที่ตัวสะท้อนแสงถอดรหัส IL ที่สร้างโดยรหัสของคุณ:

โมฆะคงที่ส่วนตัว Main (สตริง [] args)
{
    SqlConnection conn = SqlConnection ใหม่ ("... ");
    ลอง
    {
        conn.Open ();
        DoStuff ();
    }
    ในที่สุด
    {
        ถ้า (conn! = null)
        {
            conn.Dispose ();
        }
    }
}

ดังนั้นคำตอบคือใช่มันจะปิดการเชื่อมต่อหาก

สิ่งที่ควรทำ ()
โยนข้อยกเว้น


เพิ่มถ้า conn.Open () แสดงข้อยกเว้น : D
Jeff Yates

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

-1

Dispose () ไม่ถูกเรียกในรหัสนี้

class Program {
    static void Main(string[] args) {
        using (SomeClass sc = new SomeClass())
        {
            string str = sc.DoSomething();
            sc.BlowUp();
        }
    }
}

public class SomeClass : IDisposable {
    private System.IO.StreamWriter wtr = null;

    public SomeClass() {
        string path = System.IO.Path.GetTempFileName();
        this.wtr = new System.IO.StreamWriter(path);
        this.wtr.WriteLine("SomeClass()");
    }

    public void BlowUp() {
        this.wtr.WriteLine("BlowUp()");
        throw new Exception("An exception was thrown.");
    }

    public string DoSomething() {
        this.wtr.WriteLine("DoSomething()");
        return "Did something.";
    }

    public void Dispose() {
        this.wtr.WriteLine("Dispose()");
        this.wtr.Dispose();
    }
}

สิ่งนี้ตอบคำถาม OP หรือไม่?
Joey Phillips

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

คุณต้องดูไฟล์ผิด "Dispose ()" จะเขียนลงในไฟล์ temp ของคุณ ไม่มีใครอ้างว่าบล็อกโดยใช้จะจัดการกับข้อยกเว้น ลองเรียกใช้สิ่งนี้โดยไม่ใช้ดีบักเกอร์
LarsTech

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