Liệu Dispose vẫn được gọi khi ngoại lệ được đưa vào bên trong câu lệnh using?


103

Trong ví dụ dưới đây, kết nối sẽ đóng và bị loại bỏ khi một ngoại lệ được ném ra nếu nó nằm trong một usingcâu lệnh?

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

Tôi biết mã này dưới đây sẽ đảm bảo rằng nó đúng, nhưng tôi tò mò về cách sử dụng câu lệnh thực hiện nó.

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();
}

Có liên quan:

Cách thích hợp để đảm bảo kết nối SQL được đóng khi một ngoại lệ được đưa ra?

Câu trả lời:


112

Có, usinggói mã của bạn trong một khối thử / cuối cùng nơi finallyphần sẽ gọi Dispose()nếu nó tồn tại. Tuy nhiên, nó sẽ không gọi Close()trực tiếp vì nó chỉ kiểm tra IDisposablegiao diện đang được triển khai và do đó là Dispose()phương thức.

Xem thêm:


5
Chỉ cần chỉ ra trên các lớp kết nối nếu bạn phản chiếu qua chúng, bạn sẽ thấy Dispose () thực sự gọi Close () bên trong. Nếu nó ở trong tình trạng nó có thể.
Chris Marisic

2
Bạn đúng, nó đúng. Tuy nhiên, tôi cố tình không đề cập đến nó vì tôi không muốn đánh lừa mọi người nghĩ rằng điều này có liên quan gì đến IDisposable hoặc mẫu liên quan. Thực tế là việc triển khai cụ thể này gọi Close () là một chi tiết của việc triển khai, không phải là mẫu.
Jeff Yates

3
MSDN sử dụng tài liệu cũng xác nhận câu trả lời này: Câu lệnh using đảm bảo rằng Dispose được gọi ngay cả khi một ngoại lệ xảy ra trong khi bạn đang gọi các phương thức trên đối tượng. Bạn có thể đạt được kết quả tương tự bằng cách đặt đối tượng bên trong khối try và sau đó gọi Dispose trong khối cuối cùng; trên thực tế, đây là cách trình biên dịch dịch câu lệnh using.
băng thông rộng

20

Đây là cách bộ phản xạ giải mã IL do mã của bạn tạo ra:

private static void Main (string [] args)
{
    SqlConnection conn = new SqlConnection ("...");
    thử
    {
        conn.Open ();
        DoStuff ();
    }
    cuối cùng
    {
        if (conn! = null)
        {
            conn.Dispose ();
        }
    }
}

Vì vậy, câu trả lời là có, nó sẽ đóng kết nối nếu

DoStuff ()
ném một ngoại lệ.


Thêm if conn.Open () ném một ngoại lệ. : D
Jeff Yates 05/02/09

Ừ chắc chắn. Nếu bất kỳ thứ gì nằm trong khối SAU KHI mệnh đề using ném một ngoại lệ, kết nối sẽ bị đóng. Cách duy nhất mà khối cuối cùng sẽ không được thực thi là nếu "new SqlConnection (...)" ném ra, nhưng trong trường hợp đó, bạn sẽ không thực sự có một kết nối mở hợp lệ để đóng. Vậy là ổn.
Florin Sabau

-1

Dispose () không được gọi trong mã này.

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();
    }
}

Điều này có trả lời câu hỏi OP không ??
Joey Phillips

Đúng. Câu trả lời là không. Dispose () không được gọi trong mã đính kèm. Hơn nữa, ngoại lệ được ném ra không được xử lý và chương trình sẽ nổ tung.
Chad

Bạn phải xem sai tập tin. "Dispose ()" được ghi vào tệp tạm thời của bạn. Không ai tuyên bố một khối sử dụng sẽ xử lý một ngoại lệ. Hãy thử chạy điều này mà không có trình gỡ lỗi.
LarsTech

Tôi đã chạy mã chính xác này và nó gọi Dispose (). Bạn có chắc câu trả lời của bạn là đúng?
Dnomyar96
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.