2010-07-14 20 views
90

Tôi đã đoạn mã sauĐiều gì sẽ xảy ra nếu tôi trở lại trước khi kết thúc tuyên bố sử dụng? Việc vứt bỏ sẽ được gọi?

using(MemoryStream ms = new MemoryStream()) 
{ 
    //code 
    return 0; 
} 

Phương pháp dispose() được gọi vào cuối using tuyên bố niềng răng } phải không? Vì tôi return trước khi kết thúc câu lệnh using, đối tượng MemoryStream có được xử lý đúng cách không? chuyện gì xảy ra ở đây thế?

+4

@JonH: Tìm chính xác bản sao, sau đó bỏ phiếu để đóng trong trường hợp đó xin vui lòng. – Noldorin

+0

@Noldorin: Tôi đã đi tìm kiếm một sự lừa dối về điều này, bởi vì tôi đã nhận ra nó * phải * đã được hỏi trước đây, nhưng tôi không thể tìm thấy nó. Tôi đoán vẫn còn những câu hỏi dễ dàng. :) – Randolpho

+0

@JonH và @Noldorin - các bản sao sẽ được trình bày khi câu hỏi được hình thành, nó tìm kiếm "các câu hỏi tương tự", một tính năng mà mọi người dường như không sử dụng đủ. –

Trả lời

137

Có, Dispose sẽ được gọi. Nó được gọi ngay sau khi thực hiện rời khỏi phạm vi của khối using, bất kể những gì có nghĩa là nó đã rời khỏi khối, có thể là kết thúc thực hiện của khối, một tuyên bố return, hoặc một ngoại lệ.

Như @Noldorin một cách chính xác chỉ ra, sử dụng một khối using trong mã được biên dịch vào try/finally, với Dispose được gọi trong khối finally. Ví dụ đoạn mã sau:

using(MemoryStream ms = new MemoryStream()) 
{ 
    //code 
    return 0; 
} 

hiệu quả trở thành:

MemoryStream ms = new MemoryStream(); 
try 
{ 
    // code 
    return 0; 
} 
finally 
{ 
    ms.Dispose(); 
} 

Vì vậy, bởi vì finally được đảm bảo để thực hiện sau khi khối try đã hoàn tất thi công, bất kể con đường thực hiện của nó, Dispose là đảm bảo được được gọi là, không có vấn đề gì.

Để biết thêm thông tin, hãy xem this MSDN article.

Phụ Lục:
Chỉ cần một caveat chút để thêm: vì Dispose được đảm bảo để được gọi, nó gần như luôn luôn là một ý tưởng tốt để đảm bảo rằng Dispose bao giờ ném một ngoại lệ khi bạn thực hiện IDisposable. Thật không may, có một số lớp học trong thư viện lõi rằng làm ném trong một số trường hợp khi Dispose được gọi là - Tôi đang xem bạn, WCF Dịch vụ tham khảo/Client Proxy! - và khi điều đó xảy ra, có thể rất khó theo dõi ngoại lệ ban đầu nếu Dispose được gọi trong một ngoại lệ ngăn xếp ngoại lệ, vì ngoại lệ ban đầu bị nuốt theo lợi thế của ngoại lệ mới được tạo bởi cuộc gọi Dispose. Nó có thể gây phiền toái. Hay là bực mình? Một trong hai. Có thể là cả hai.

+4

Tôi nghĩ bạn sẽ thấy nó được biên dịch một cách hiệu quả thành một khối thử cuối cùng với một lệnh gọi là 'Vứt bỏ' cuối cùng, vì vậy nó có hiệu quả trong việc thực hiện 'cuối cùng', như bạn mô tả. – Noldorin

+0

@Noldorin: chính xác. Mặc dù tôi cho rằng tôi có thể rõ ràng về điều đó. Chỉnh sửa sắp tới .... – Randolpho

+0

Câu trả lời đơn giản và hiệu quả, đã bỏ phiếu của tôi. :) – Noldorin

4

Đối tượng MemoryStream của bạn sẽ được xử lý đúng cách, không cần phải lo lắng về điều đó.

0

Hãy nhìn vào mã của bạn trong phản xạ sau khi bạn biên dịch nó. Bạn sẽ thấy rằng trình biên dịch tái cấu trúc mã để đảm bảo rằng việc vứt bỏ được gọi trên luồng.Các báo cáo

14

using hoạt động chính xác như try ... finally khối, do đó sẽ luôn thực thi trên mọi đường dẫn thoát mã. Tuy nhiên, tôi tin rằng chúng phải tuân theo các tình huống rất hiếm và hiếm hoi trong đó các khối finally không được gọi. Một ví dụ mà tôi có thể nhớ là nếu luồng tiền cảnh thoát ra trong khi các luồng nền đang hoạt động: tất cả các luồng ngoài GC được tạm dừng, nghĩa là các khối finally không chạy.

Chỉnh sửa rõ ràng: chúng hoạt động giống với logic cho phép chúng xử lý các đối tượng IDisposable, d'oh.

Bonus nội dung: chúng có thể được xếp chồng lên nhau (nơi các loại khác):

using (SqlConnection conn = new SqlConnection("string")) 
using (SqlCommand comm = new SqlCommand("", conn)) 
{ 

} 

Và cũng dấu phẩy phân cách (nơi các loại đều giống nhau):

using (SqlCommand comm = new SqlCommand("", conn), 
     SqlCommand comm2 = new SqlCommand("", conn)) 
{ 

} 
Các vấn đề liên quan