Câu trả lời:
Như một số người khác đã chỉ ra nói chung đây không phải là một vấn đề.
Trường hợp duy nhất nó sẽ gây ra cho bạn các vấn đề là nếu bạn quay lại giữa câu lệnh đang sử dụng và trả về biến sử dụng. Nhưng một lần nữa, điều này cũng sẽ gây ra sự cố cho bạn ngay cả khi bạn không quay lại và chỉ cần giữ một tham chiếu đến một biến.
using ( var x = new Something() ) {
// not a good idea
return x;
}
Cũng tệ
Something y;
using ( var x = new Something() ) {
y = x;
}
return
câu lệnh làm cho phần cuối của using
khối không thể truy cập được bởi bất kỳ đường dẫn mã nào. Phần cuối của using
khối cần được chạy để có thể xử lý đối tượng nếu cần.
Nó hoàn toàn ổn.
Bạn đang nghĩ rằng
using (IDisposable disposable = GetSomeDisposable())
{
//.....
//......
return Stg();
}
được dịch một cách mù quáng thành:
IDisposable disposable = GetSomeDisposable()
//.....
//......
return Stg();
disposable.Dispose();
Điều đó, thừa nhận, sẽ là một vấn đề, và sẽ đưa ra using
tuyên bố khá vô nghĩa --- đó là lý do tại sao đó không phải là những gì nó làm.
Trình biên dịch đảm bảo rằng đối tượng được xử lý trước khi điều khiển rời khỏi khối - bất kể nó rời khỏi khối như thế nào.
Điều đó hoàn toàn tốt - không có vấn đề gì cả. Tại sao bạn tin rằng nó sai?
Một tuyên bố sử dụng chỉ là đường cú pháp cho một khối thử / cuối cùng, và như Grzenio nói rằng cũng tốt để trở về từ một khối thử.
Biểu thức trả về sẽ được ước tính, sau đó khối cuối cùng sẽ được thực thi, sau đó phương thức sẽ trả về.
Điều đó là hoàn toàn chấp nhận được. Một tuyên bố sử dụng đảm bảo đối tượng IDis Dùng sẽ được xử lý bất kể điều gì.
Từ MSDN :
Câu lệnh sử dụng đảm bảo rằng Dispose được gọi ngay cả khi có 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 vào trong khối thử và sau đó gọi Dispose trong khối cuối cùng; trong thực tế, đây là cách sử dụng câu lệnh được dịch bởi trình biên dịch.
Mã dưới đây cho thấy cách using
làm việc:
private class TestClass : IDisposable
{
private readonly string id;
public TestClass(string id)
{
Console.WriteLine("'{0}' is created.", id);
this.id = id;
}
public void Dispose()
{
Console.WriteLine("'{0}' is disposed.", id);
}
public override string ToString()
{
return id;
}
}
private static TestClass TestUsingClose()
{
using (var t1 = new TestClass("t1"))
{
using (var t2 = new TestClass("t2"))
{
using (var t3 = new TestClass("t3"))
{
return new TestClass(String.Format("Created from {0}, {1}, {2}", t1, t2, t3));
}
}
}
}
[TestMethod]
public void Test()
{
Assert.AreEqual("Created from t1, t2, t3", TestUsingClose().ToString());
}
Đầu ra:
't1' được tạo.
't2' được tạo.
't3' được tạo.
'Được tạo từ t1, t2, t3' được tạo.
't3' được xử lý.
't2' được xử lý.
't1' được xử lý.
Các xử lý được gọi sau câu lệnh return nhưng trước khi thoát hàm.
Có lẽ không đúng 100% rằng điều này được chấp nhận ...
Nếu bạn tình cờ được sử dụng lồng và trở về từ bên trong một cái lồng, nó có thể không an toàn.
Lấy điều này làm ví dụ:
using (var memoryStream = new MemoryStream())
{
using (var textwriter = new StreamWriter(memoryStream))
{
using (var csv = new CsvWriter(textwriter))
{
//..write some stuff to the stream using the CsvWriter
return memoryStream.ToArray();
}
}
}
Tôi đã chuyển qua một DataTable để được xuất ra dưới dạng csv. Với sự trở lại ở giữa, nó đã ghi tất cả các hàng vào luồng, nhưng csv xuất ra luôn thiếu một hàng (hoặc nhiều, tùy thuộc vào kích thước của bộ đệm). Điều này nói với tôi rằng một cái gì đó không được đóng lại đúng cách.
Cách chính xác là đảm bảo tất cả các lần sử dụng trước được xử lý đúng cách:
using (var memoryStream = new MemoryStream())
{
using (var textwriter = new StreamWriter(memoryStream))
{
using (var csv = new CsvWriter(textwriter))
{
//..write some stuff to the stream using the CsvWriter
}
}
return memoryStream.ToArray();
}