2009-08-20 29 views
11

Tôi nhận được các nguyên tắc cơ bản của bao đóng và biểu thức lambda nhưng tôi đang cố gắng che giấu những gì đang xảy ra đằng sau hậu trường và khi nó là/không thực tế để sử dụng chúng trong mã của tôi. Hãy xem xét ví dụ sau, có một bộ sưu tập tên và trả về bất kỳ tên nào bắt đầu bằng chữ cái C ...Đóng cửa và Lambda trong C#

Trước tiên, có cách nào trực tiếp hơn để tôi có thể viết biểu thức này không? Thứ hai, không phải là "FindAll" sẽ cấp phát bộ nhớ cho một bộ sưu tập mới chứa các mục phù hợp? Tôi chắc chắn thấy rằng cú pháp là thanh lịch hơn, nhưng tôi muốn chắc chắn rằng tôi không đi vào các vấn đề hiệu suất sau đó xuống đường khi làm việc với các bộ sưu tập lớn hơn. Liệu trình biên dịch làm một số voodoo tối ưu hóa đằng sau hậu trường mà làm cho mối quan tâm của tôi không hợp lệ?

Trả lời

15

Có, FindAll sẽ tạo danh sách mới. Bạn muốn "ở đâu", mà sẽ trả về một đối tượng IEnumerable mà biết làm thế nào để vòng qua danh sách hiện tại của bạn:

foreach (string name in names.Where(n => n.StartsWith("C"))) 
{ 
    Console.WriteLine(name); 
} 

Nhưng không có đóng cửa trong mã đó, vì không có biến địa phương để nắm bắt.

+0

Ok, vì vậy có thể tôi chưa hoàn toàn hiểu được các khái niệm cơ bản về đóng cửa. Tuy nhiên, tất cả các câu trả lời tôi nhận được ở đây đều tuyệt vời và di chuyển tôi xa hơn một chút trên con đường ... cảm ơn, tất cả mọi người. – lJohnson

+1

Điều đó giải thích cho tôi sự khác biệt giữa các bao đóng và lambda: "không đóng mã trong đó, bởi vì không có biến cục bộ nào để nắm bắt." – TLDR

2

Bạn nên sử dụng Where thay vì FindAll. Where sẽ lặp qua bộ sưu tập cho điều kiện của bạn và cho phép bạn thực hiện hành động của mình, thay vì tạo bộ sưu tập mới đáp ứng điều kiện của bạn, sau đó lặp lại THAT và thực hiện hành động của bạn.

2

Bạn có quyền sử dụng phương pháp List<T>.FindAll sẽ tạo và trả lại List<T> mới.

Nếu bạn có thể sử dụng LINQ sau đó có rất nhiều phương pháp mà dòng kết quả của họ một mục tại một thời điểm, nếu có thể, thay vì trở về một bộ sưu tập đầy đủ dân cư:

foreach (var i in names.Where(x => x.StartsWith("C"))) 
{ 
    Console.WriteLine(i); 
} 

Không có built-in ForEach phương pháp mà tác động lên IEnumerable<T>, nhưng nó tầm thường để viết phần mở rộng của riêng bạn nếu bạn thực sự cần chức năng:

names.Where(x => x.StartsWith("C")).ForEach(Console.WriteLine); 

// ... 

public static void ForEach<T>(this IEnumerable<T> source, Action<T> action) 
{ 
    foreach (T item in source) 
    { 
     action(item); 
    } 
} 
+1

Đây chính là cách tôi sẽ làm. Tôi cũng đã đề cập rằng việc tạo danh sách có thể được đơn giản hóa: 'Liệt kê tên = Danh sách mới {" Alan "," Bob "," Chris "," Dave "," Edgar "," Frank "}; ' –

12

Những câu trả lời khác mà nói để sử dụng "ở đâu" là chính xác. Một điểm bổ sung: Bạn cũng có thể sử dụng cú pháp truy vấn hiểu biết để làm cho "Where" trông đẹp hơn:

var query = from name in names where name.StartsWith("C") select name; 
    foreach(var result in query) Console.WriteLine(result); 

Lưu ý rằng khi một mối quan tâm về kiểu dáng, tôi khuyên rằng biểu thức không có tác dụng phụ và tuyên bố luôn luôn có tác dụng phụ. Do đó, cá nhân tôi sẽ sử dụng tuyên bố foreach thay vì biểu diễn phụ của OneEach để thực hiện hiệu ứng bên đầu ra. Nhiều người không đồng ý với điều này, nhưng tôi nghĩ nó làm cho mã rõ ràng hơn.

+3

một đại hội tuyệt vời! –

0

Điều gì làm cho một biểu thức cụ thể là việc đóng là phạm vi từ vựng, phải không?

string prefix = "C"; 
// value of prefix included in scope 
names.FindAll(x => x.StartsWith(prefix)).ForEach(...);  

hoặc thậm chí

Func filter = null; 

{ 
    string prefix = "C"; 
    // value of prefix included in scope 
    filter = x => x.StartsWith (prefix);  
} 

// find all names starting with "C" 
names.FindAll (filter).ForEach (...);  

Hoặc tôi thiếu một cái gì đó hoặc làm cho các giả định không có cơ sở?