2009-10-23 36 views
13

Tôi vẫn chưa hoàn toàn hiểu được việc đóng cửa là như thế nào vì vậy tôi đã đăng hai ví dụ này và tôi muốn biết liệu các ví dụ này có bị đóng cả hai hay không?Những ví dụ này có phải là C# không?

Ví dụ A:

List<DirectoryInfo> subFolders = new List<DirectoryInfo>(); 

Action<string> FilterSubFoldersStartA = 
    s => subFolders. 
     AddRange((new DirectoryInfo(s)).GetDirectories(). 
     Where(d => d.Name.StartsWith("A"))); 

FilterSubFoldersStartA(@"c:\tempa"); 
FilterSubFoldersStartA(@"c:\tempb"); 

Ví dụ B:

List<DirectoryInfo> subFolders = new List<DirectoryInfo>(); 

string filter = "A"; 

Action<string> FilterSubFoldersStartGen = 
    s => subFolders. 
     AddRange((new DirectoryInfo(s)).GetDirectories(). 
     Where(d => d.Name.StartsWith(filter))); 

FilterSubFoldersStartGen(@"c:\tempa"); 

filter = "B"; 

FilterSubFoldersStartGen(@"c:\tempb"); 

Trả lời

6

Yea, đóng cửa là không có gì hơn một chức năng mà "tiết kiệm" một số biến từ môi trường trong đó nó được định nghĩa. Vì vậy, trong cả hai ví dụ của bạn, hành động được xác định sẽ lưu danh sách có tên là subFolders, có thể được tham chiếu bởi các hàm ngay cả sau khi biến cục bộ nằm ngoài phạm vi. Biến số filter trong ví dụ thứ hai cũng được lưu bởi hàm được xác định.

Một định nghĩa chính xác hơn here

9

ví dụ thứ hai của bạn tận dụng đóng cửa (về mặt kỹ thuật bạn có thể nói rằng trình biên dịch tính đóng cửa trong cả hai trường hợp, nhưng bạn không tận dụng nó trong trường hợp đầu tiên).

Việc đóng đơn giản là "tất cả các biến có thể nhìn thấy được đối với hàm này". Không hơn không kém. Và rõ ràng, trong cả hai trường hợp, các biến đó tồn tại và được trình biên dịch xác định. Nhưng những gì chúng ta thường có nghĩa là khi chúng ta nói về "sử dụng bao đóng" là các biểu thức lambda có thể sử dụng tất cả các biến cục bộ hiển thị tại vị trí chúng được khai báo. Tất cả chúng đều là một phần của việc đóng cửa.

Trong trường hợp của bạn, d chỉ đơn giản là tham số cho hàm lambda và vì đó là tất cả những gì bạn sử dụng trong trường hợp đầu tiên, bạn không thực sự tận dụng lợi thế của các bao đóng.

Trong trường hợp thứ hai, filter không được xác định trong biểu thức lambda, nó không phải là tham số hoặc bất kỳ thứ gì. Đó là một biến địa phương mà chỉ xảy ra như vậy sẽ được hiển thị tại nơi mà lambda được khai báo. Vì vậy, nó là một phần của đóng cửa lambda, cho phép bạn tham khảo nó trong cơ thể của lambda.

Chỉnh sửa
Như đã nêu trong các nhận xét, tôi không đọc mã quá gần. Tôi chỉ chú ý đến biểu thức lambda thứ hai trong mỗi ví dụ. Lambda đầu tiên không sử dụng bao đóng (nó đóng trên subFolders trong cả hai trường hợp.)

+2

Ví dụ đầu tiên đóng trên 'thư mục con' để nó cũng bị đóng. –

+0

Ồ đúng, tôi thậm chí còn không chú ý đến lambda đầu tiên. Tôi chỉ nhìn thấy một 'd => ...' một. Bạn đúng. Cái đầu tiên đóng trên 'subFolders', và trong trường hợp thứ hai, lambda thứ hai đóng trên' filter'. – jalf

0

Cả hai ví dụ đều có đóng. Trong phương thức "A" ẩn danh, hãy ghi lại các biến con của biến cục bộ. Trong phương thức ẩn danh "B", hãy nắm bắt các biến con của bộ lọc con và bộ lọc cục bộ. Ngoài ra hãy xem here.

P.S. Cũng lưu ý rằng bạn đang thực sự sử dụng đóng trong "A" bởi vì bạn đang sử dụng biến subFolders.

0

Dưới đây là ví dụ từ http://www.agileatwork.com/a-proper-closure-in-csharp/ về nội dung có thể trông quen thuộc hơn một chút nếu bạn thấy thoải mái với JavaScript. Một đóng được tạo ra xung quanh biến số tax để tính toán chỉ được thực hiện một lần. Nó không phải là chính xác dễ dàng trên đôi mắt, nhưng nó là mát mẻ mà bạn có thể làm điều này loại điều trong C#.

public class Order 
{ 
    public Order(ITaxCalculator taxCalculator) 
    { 
     CalculateTax = new Func<Func<decimal>>(() => 
     { 
      decimal? tax = null; 
      return() => 
      { 
       if (!tax.HasValue) 
       { 
        tax = taxCalculator.Calculate(this); 
       } 
       return tax.Value; 
      }; 
     })(); 
    } 

    public Func<decimal> CalculateTax { get; set; } 

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