2010-02-04 43 views
14

Có tương đương không?Sử dụng vs lambda

 public static void Using<T>(this T disposable, Action<T> action) 
      where T:IDisposable 
     { 
      try { 
       action(disposable); 
      } 
      finally { 
       disposable.Dispose(); 
      } 
     } 

     new SqlConnection("").Using(conn => { 

     }); 

     using(var conn = new SqlConnection("")){ 

     }; 

nói cách khác, chúng tôi có thể thay thế bằng từ khóa bằng phương pháp này không?

+5

Bạn cũng có thể xem bài viết này: http://marcgravell.blogspot.com/2009/11/selectmany-combining-idisposable-and.html bởi Marc Gravell. –

+3

Câu hỏi trung thực: Tại sao bạn muốn? – Justin

+1

Dao cạo của Occam. – dotneter

Trả lời

19

Tôi không nghĩ rằng đây là một ý tưởng đặc biệt tốt, bởi vì nó cũng sẽ cho phép chúng tôi viết

var conn = new SqlConnecction(""); 
conn.Using(c => /* do something with c */); 
conn.Open(); 

này sẽ biên dịch, nhưng khi bạn đạt đến dòng cuối cùng, nó sẽ ném một ObjectDisposedException.

Trong mọi trường hợp, thành ngữ mã hóa using nổi tiếng, vậy tại sao các nhà phát triển đồng nghiệp của bạn khó đọc mã của bạn?

+11

Điều đó cũng có thể xảy ra với câu lệnh 'using" cổ điển: 'var conn = ...; sử dụng (conn) {...}; conn.Open(); ' – Heinzi

+0

Tôi xem xét việc thay thế này chỉ theo lý thuyết, như sử dụng nguyên lý dao cạo của Occam. – dotneter

+3

@Heinzi Đó là lý do tại sao chúng ta thực thi các tiêu chuẩn mã hóa của chúng ta rằng đối tượng trong mệnh đề sử dụng cũng được định nghĩa trong mệnh đề using - tức là 'using (IDbConnection con = ...) {...}' –

2

Một giới hạn: bạn không thể đưa ra các tham số của phương pháp chứa trong lambda của bạn.

2

Séc séc using cho số disposablenull. Khác với thời gian chạy, bạn sẽ nhận được chủ yếu là hành vi tương tự (ngoài các stack frame bổ sung, và các cuộc gọi đại biểu).

1

Như Richard đã nói, có một cuộc gọi phương thức bổ sung giữa việc tạo đối tượng dùng một lần và bắt đầu thử. Điều này làm tăng khung thời gian trong đó một ngoại lệ không đồng bộ có thể xảy ra, dẫn đến đối tượng dùng một lần của bạn không được xử lý. Tuy nhiên, đây không phải là một vấn đề lớn, bởi vì các kiểu thực hiện IDisposable không nên lấy tài nguyên của chúng trong hàm tạo (SqlConnection thu hút tài nguyên của nó trong khi gọi phương thức Open()).

Vì vậy, trong khi cách viết mới của bạn bằng văn bản sử dụng báo cáo sẽ làm việc, nó làm cho đọc cho các nhà phát triển khác khó khăn hơn nhiều và có thể dễ dàng bị lạm dụng theo cách Mark Seemann ghi chú.

Vì vậy, bạn có thể thay thế từ khóa đang sử dụng bằng phương pháp Sử dụng tiện ích mở rộng của mình không? Vâng. Bạn nên làm điều đó? Số

2

Một số lý do khiến tôi không muốn sử dụng điều này.

Compile-Time foolproofing

using (var foo=new Bar()) 
{ 
    foo=new Bar();// throws an error at compile time 
} 

Struct thực hiện IDisposable

Struct giao diện thực hiện được đóng hộp khi một phương pháp giao diện được gọi vào chúng. Tuyên bố sử dụng đủ thông minh để nhận ra khi nào mục tiêu của nó là cấu trúc tại thời gian biên dịch và tha thứ cho quyền anh.

+1

Về mặt kỹ thuật, bit về cấu trúc thực sự là một lỗi trình biên dịch. Các spec nói để làm việc chuyển đổi quyền anh; việc thực hiện không làm như vậy; nó chỉ gọi Dispose() trực tiếp. Điều này được cho là điều "chính xác hơn" để làm anyway; nếu disposer làm thay đổi cấu trúc, thì có thể nó sẽ biến đổi bản gốc, chứ không phải là bản sao được đóng hộp. –

+0

Nó không phải là một lỗi, nó là một tính năng của các phiên bản CLR trong tương lai sau đó;) –

10

Tôi lưu ý rằng phương pháp của bạn không làm mọi thứ mà câu lệnh "đang sử dụng". Ví dụ, nó không giới thiệu một không gian khai báo biến cục bộ mới trong đó một biến chứa trên tài nguyên có thể được khai báo.

Cũng không cho phép nhiều tài nguyên dùng một lần cùng loại được khai báo tất cả cùng một lúc.

Và cuối cùng, nó dường như không sáng tác đặc biệt thanh lịch với chính nó.Một trong những điều tốt đẹp về "sử dụng" như một tuyên bố là bạn có thể nói:

using(something) 
using(someotherthing) 
using(somethirdthing) 
{ 
    use all three, they'll all get disposed 
} 

Điều đó sẽ trông như thế nào trong đề xuất của bạn?

something.Using(
x=>someotherthing.Using(
y=>somethirdthing.Using(
z=> { use all three }))); 

Một chút tổng, thẳng thắn.

0

Đó là gần nhưchức năng tương đương tương đương, nhưng thực tế nói nó không mang lại bất kỳ lợi ích nào. Ngữ nghĩa của tuyên bố "truyền thống" using được biết đến và tiêu chuẩn. Trong khi cách tiếp cận của bạn có thể giống nhau (mặc dù có một số khác biệt), nó giới thiệu chi phí và sự phức tạp không cần thiết - không chỉ bạn có các lời gọi phương thức bổ sung mà bạn đang tự sao chép mã trình biên dịch sẽ tự động tạo ra.

0

số Bạn đang giảm hạng từ khóa ngôn ngữ [nghĩa là trình biên dịch có thể thực hiện một số thứ xung quanh nó như được chỉ ra bởi Florian] cho một cuộc gọi phương thức thông thường.

Mặc dù ngữ nghĩa chúng có thể giống nhau, trình biên dịch sẽ không biết phương thức sẽ làm. Kiểm tra thời gian biên dịch tốt hơn các ngoại lệ thời gian chạy, như chúng ta đều biết.

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