2009-09-02 26 views
15

Câu lệnh using (...) là cú pháp đường để thử {} cuối cùng {}.Sử dụng câu lệnh và try-catch() - cuối cùng là lặp lại?

Nhưng nếu tôi sau đó có một tuyên bố sử dụng như dưới đây:

using (FileStream fs = File.Open(path)) 
{ 


} 

Bây giờ tôi muốn nắm bắt những trường hợp ngoại lệ rằng việc mở tập tin này có thể gây ra (và điều này là mã có nguy cơ khá cao ở chỗ nó có thể thất bại do môi trường), nhưng nếu tôi viết try-catch bên trong sẽ không được lặp lại? Khi mã được biên dịch sang IL, tôi cho rằng sự lặp lại sẽ bị xóa khi mã được JITted?

Tuy nhiên, tôi muốn nắm bắt các ngoại lệ khi mở tệp có thể gây ra (vì vậy tôi nên bọc thử bên ngoài phạm vi của câu lệnh) và cũng là ngoại lệ cho bất kỳ điều gì tôi thực hiện trong khối sử dụng. việc cố gắng nắm bắt bên trong khối.

Điều này có vẻ như tôi đang thêm rất nhiều sự lặp lại cho những gì CLR có thể làm bên trong. CLR có thêm mệnh đề bắt không?

Đồng nghiệp của tôi lập luận rằng câu lệnh sử dụng lộn xộn (nhưng điều này là do một dòng duy nhất hơi dài do tôi mã hóa chúng khi tôi cần thay đổi chúng rất nhanh và không có quyền truy cập vào các phần khác của mã căn cứ). Đồng nghiệp cho biết không sử dụng tuyên bố sử dụng nhưng có bao giờ có bất kỳ sự khác biệt chức năng nào giữa câu lệnh sử dụng và try-finally/try-catch-finally không? Tôi đã thấy một trường hợp này, nơi các dịch vụ WCF có một trường hợp góc không nổi tiếng về việc sử dụng các giá trị cuối cùng và trả về (một cái gì đó về cuối cùng). Giải pháp là sử dụng một khối kiểm tra. Có bất cứ điều gì như thế này trong C#?

Một lưu ý khác là tất cả các loại triển khai IDisposale chủ sở hữu tài nguyên không được quản lý? Một cuộc thảo luận với bạn tôi đã chỉ ra câu trả lời là không. (Tôi cũng đã đọc một số chủ đề trong phần sử dụng của diễn đàn này, một số kiến ​​thức rất tốt ở đó).

Trả lời

7

Bạn có thể tự triển khai mẫu nếu bạn cần xử lý một số ngoại lệ nếu bạn thực sự muốn. Cá nhân, tôi vẫn tìm thấy nó đơn giản hơn (và quan trọng hơn, rõ ràng hơn) để chỉ sử dụng trong khối try/catch.

Nhưng nếu bạn tự làm, hãy đảm bảo bạn làm đúng. Khối Using cũng tạo khối phạm vi ẩn danh để biến của bạn đủ điều kiện để thu thập sớm hơn. Phương thức .Dispose() được gọi ở cuối khối Using chỉ dọn dẹp tài nguyên không được quản lý và do đó mọi bộ nhớ mà đối tượng của bạn giữ lại có thể bị treo lâu hơn một chút. Nó không có khả năng là một mối quan tâm lớn, nhưng nó là giá trị ghi nhớ chỉ trong trường hợp.

Vì vậy, để làm một thích ứng trực tiếp của mô hình, mã của bạn cần phải trông như thế này:

{ 
    FileStream fs; 
    try 
    { 
     fs = File.Open(path); 

    } 
    catch (FileNotFoundException e) { /* ... */ } 
    catch (IOException e) { /* ... */ } 
    catch (Exception e) {/* ... */} 
    finally 
    { 
     if (fs != null) fs.Dispose(); 
    } 
} 

Cá nhân, tôi muốn xem Using mở rộng để hỗ trợ CatchFinally khối. Vì họ đã thực hiện một phép biến đổi trên mã, nó không có vẻ như thế này sẽ thêm nhiều phức tạp hơn nữa.

+0

Sử dụng hỗ trợ cuối cùng mặc dù? Bạn đã tìm hiểu về cách sử dụng, sử dụng khối phạm vi ẩn danh ở đâu? Tôi muốn biết thêm về điều này. Vì vậy, khi tôi mở một tập tin trong một khối sử dụng (ví dụ như FileSream.Open()), ngoại lệ này sẽ bong bóng lên. Nếu câu lệnh sử dụng thực hiện try/finally, tôi phải bọc nó trong try/catch chỉ để có catch. – dotnetdev

4

Nếu bạn cần xử lý rõ ràng các trường hợp đặc biệt khác nhau có thể xảy ra trong tuyên bố, bạn có thể thay thế using bằng try/catch/finally và gọi số Dispose() một cách rõ ràng. Hoặc bạn có thể đặt try/catch xung quanh khối using để tách các trường hợp ngoại lệ khỏi việc đảm bảo thải bỏ.

Chỉ điều using đảm bảo Dispose() được gọi ngay cả khi ngoại lệ được ném vào trong khối. Đó là việc triển khai rất hạn chế, cụ thể về cấu trúc chung của try/[catch]/finally.

Điều quan trọng là không có tùy chọn nào trong số này có bất kỳ tác động thực sự nào - miễn là nó thực hiện những gì bạn cần, có thể đọc và dễ hiểu, ai quan tâm? Nó không giống như một thử thêm sẽ là một nút cổ chai hoặc bất cứ điều gì!

Để trả lời câu hỏi cuối cùng của bạn - không, IDisposable chắc chắn không nhất thiết có nghĩa là người triển khai có thể xử lý các tài nguyên không được quản lý. Đó là một mô hình đơn giản hơn và chung chung hơn thế. Dưới đây là một ví dụ hữu ích:

public class Timer : IDisposable 
{ 
    internal Stopwatch _stopwatch; 
    public Timer() 
    { 
     this._stopwatch = new Stopwatch(); 
     this._stopwatch.Start(); 
    } 

    public void Dispose() 
    { 
     this._stopwatch.Stop(); 
    } 
} 

Chúng ta có thể sử dụng để lần thứ mà không cần phải dựa một cách rõ ràng về bắt đầu và dừng lại được gọi bằng cách sử dụng:

using(Timer timer = new Timer()) 
{ 
    //do stuff 
} 
4

Sự khác biệt lớn nhất giữa việc sử dụng và thử-cuối cùng là sử dụng sẽ chỉ gọi phương thức Dispose().Nếu bạn thực hiện khối cuối cùng của riêng bạn có thể làm logic khác, ví dụ như đăng nhập, mà sẽ không được bao gồm trong việc sử dụng.

+0

+1 cho độ ngắn –

7

Sở thích của tôi là giữ nguyên câu lệnh sử dụng và bọc nó trong một lần thử/nắm bắt. Thử/nắm bắt bên ngoài sẽ bắt bất kỳ ngoại lệ nào bạn cần xem, trong khi bỏ qua Dispose(). Điều này có thêm lợi thế của việc bảo vệ bạn khỏi chính mình nếu bạn cấu trúc lại sau này để di chuyển try/catch ở nơi khác (như trong một hàm gọi).

Theo như câu hỏi của bạn về IDisposable: Bất kỳ ai cũng có thể triển khai điều này vì bất kỳ lý do nào họ thích. Không có lý do kỹ thuật nào để nó bị hạn chế đối với các tài nguyên không được quản lý. (Có hay không nên bị giới hạn đối với tài nguyên không được quản lý trong của bạn là một câu hỏi khác).

3

Cấu trúc using là viết tắt của khối try/finally. Đó là, trình biên dịch tạo:

FileStream fs = null; 
try 
{ 
    fs = File.Open(path); 
    // ... 
} 
finally 
{ 
    if (fs != null) 
     fs.Dispose(); 
} 

Vì vậy, nó là thích hợp để sử dụng using nếu bạn không cần một catch, nhưng nếu bạn làm sau đó bạn chỉ nên sử dụng một bình thường try/catch/finally.

+2

Không có gì sai khi gói 'sử dụng' chính nó trong 'try' /' catch'. Nó rõ ràng hơn 'cuối cùng' bởi vì nó là ngay lập tức rõ ràng những gì các nguồn lực được giải phóng sau khi thoát khỏi khối mà không cần phải nhìn vào' cuối cùng'. –

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