2010-03-05 21 views
10

LƯU Ý: Ngay trước khi đăng câu hỏi này nó xảy ra với tôi có một cách tốt hơn để làm những gì tôi đã cố gắng để hoàn thành (và tôi cảm thấy khá ngu ngốc về nó):Tôi đang thiếu gì trong chuỗi các biến vị ngữ này?

IEnumerable<string> checkedItems = ProductTypesList.CheckedItems.Cast<string>(); 
filter = p => checkedItems.Contains(p.ProductType); 

Vì vậy, OK, vâng, tôi đã nhận ra điều này. Tuy nhiên, tôi vẫn đăng câu hỏi, bởi vì tôi vẫn không hiểu tại sao những gì tôi (ngu ngốc) cố gắng để không hoạt động.


Tôi nghĩ điều này sẽ cực kỳ dễ dàng. Hóa ra nó khiến tôi đau đầu.

Ý tưởng cơ bản: hiển thị tất cả các mục có giá trị thuộc tính ProductType được chọn trong CheckedListBox.

Việc thực hiện:

private Func<Product, bool> GetProductTypeFilter() { 
    // if nothing is checked, display nothing 
    Func<Product, bool> filter = p => false; 

    foreach (string pt in ProductTypesList.CheckedItems.Cast<string>()) { 
     Func<Product, bool> prevFilter = filter; 
     filter = p => (prevFilter(p) || p.ProductType == pt); 
    } 

    return filter; 
} 

Tuy nhiên, nói các mục "Vốn chủ sở hữu" và "ETF" đều được kiểm tra trong ProductTypesList (một CheckedListBox). Sau đó, đối với một số lý do, đoạn mã sau chỉ trả lại sản phẩm thuộc loại "ETF":

var filter = GetProductTypeFilter(); 
IEnumerable<Product> filteredProducts = allProducts.Where(filter); 

tôi đoán nó có thể có một cái gì đó để làm với một số hỗn độn tự tham khảo nơi filter được thiết lập để, về cơ bản, bản thân hoặc thứ khác. Và tôi nghĩ rằng có thể sử dụng ...

filter = new Func<Product, bool>(p => (prevFilter(p) || p.ProductType == pt)); 

... sẽ thực hiện thủ thuật, nhưng không may mắn như vậy. Ai có thể nhìn thấy những gì tôi đang thiếu ở đây?

Trả lời

9

Tôi tin rằng bạn có vấn đề về đóng cửa đã được sửa đổi tại đây. Tham số pt được gắn vào biểu thức lambda nhưng thay đổi khi vòng lặp diễn ra. Điều quan trọng là nhận ra khi một biến được tham chiếu trong một lambda đó là biến được ghi lại, không phải là giá trị của biến số.

Trong các vòng này có phân nhánh rất quan trọng - vì biến vòng lặp đang thay đổi, không được định nghĩa lại. Bằng cách tạo một biến số bên trong vòng lặp, bạn đang tạo một biến mới cho mỗi lần lặp - sau đó cung cấp lambda để nắm bắt từng biến độc lập.

Việc thực hiện mong muốn sẽ là:

foreach (string pt in ProductTypesList.CheckedItems.Cast<string>()) { 
    string ptCheck = pt; 
    Func<Product, bool> prevFilter = filter; 
    filter = p => (prevFilter(p) || p.ProductType == ptCheck); 
} 

Eric Lippert đã viết về tình hình cụ thể này:

Một lso, xem câu hỏi Access to Modified Closure (2) để có giải thích tốt về những gì xảy ra với các biến đóng.Ngoài ra còn có một loạt các bài báo trên blog The Old New Thing có một góc nhìn thú vị về vấn đề này:

+0

Vâng, điều đó có ý nghĩa hoàn hảo. Cảm ơn! –

2

Nó đã làm với đóng cửa . Biến pt sẽ luôn tham chiếu đến giá trị cuối cùng của vòng lặp for.

xem xét ví dụ sau đây, nơi sản lượng là một trong những mong đợi vì nó sử dụng một biến được đặt phạm vi bên trong vòng lặp for.

public static void Main(string[] args) 
{ 
    var countries = new List<string>() { "pt", "en", "sp" }; 

    var filter = GetFilter(); 

    Console.WriteLine(String.Join(", ", countries.Where(filter).ToArray())); 
} 

private static Func<string, bool> GetFilter() 
{ 
    Func<string, bool> filter = p => false; 

    foreach (string pt in new string[] { "pt", "en" }) 
    { 
     Func<string, bool> prevFilter = filter; 

     string name = pt; 

     filter = p => (prevFilter(p) || p == name); 
    } 

    return filter; 
} 
2

Vì bạn đang lặp và tự đặt loại bộ lọc, bạn sẽ đặt loại sản phẩm thành pt cuối cùng trong mỗi trường hợp. Đó là một kết thúc sửa đổi và vì nó chậm trễ bị ràng buộc, bạn cần phải sao chép nó trên mỗi vòng lặp, như thế này:

foreach (string pt in ProductTypesList.CheckedItems.Cast<string>()) { 
    var mypt = pt; 
    Func<Product, bool> prevFilter = filter; 
    filter = p => (prevFilter(p) || p.ProductType == mypt); 
} 

này nên dẫn đến kết quả đúng, nếu không thì cuối cùng pt được sử dụng cho tất cả các kiểm tra bình đẳng.

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