2016-02-11 22 views
6

tôi phải truy vấn bộ sưu tập như thế này:biểu LINQ như tham số

myList.Where(s => myFilters.Contains(s.CountryCode)) 

s.CountryCode ở trên là một ví dụ. Tôi muốn biến nó thành các cột khác nhau, như sau:

myList.Where(s => myFilters.Contains(s.City)) 
myList.Where(s => myFilters.Contains(s.Region)) 
myList.Where(s => myFilters.Contains(s.Zipcode)) 

Vì vậy, tôi muốn xác định hàm trong đó biểu thức cột là một tham số. Chữ ký của hàm đó là gì?

public void MySelect(???) 
{ 
    myList.Where(s => myFilters.Contains(???); 
} 

myList là một ObservableCollection, và myFiltersList<string>

+0

Tôi nghĩ bạn nên xác định loại biến. –

+1

Nó phụ thuộc vào kiểu dữ liệu 'myFilters'. Vui lòng mở rộng câu hỏi của bạn với thông tin này. –

+0

@VadimMartynov Tôi không hiểu .... tại sao bạn cần biết loại dữ liệu myfilters – Viru

Trả lời

10

Đặt phương pháp mở rộng này trong một lớp tĩnh:

public static IEnumerable<T> WhereContains<T, TValue> (this IEnumerable<T> obj, IEnumerable<TValue> container, Func<T, TValue> propertyAccess) 
{ 
    return obj.Where(o => container.Contains(propertyAccess(o))); 
} 

Cách này ví dụ phương thức căng thẳng hoạt động là nó chấp nhận một hàm lambda để giải quyết thuộc tính cho một đối tượng thuộc kiểu của bạn. Vì vậy, bạn chỉ cần vượt qua một lamba đơn giản như x => x.City với nó.

Vì nó hoàn toàn chung chung và không cụ thể với bộ sưu tập myFilters của bạn, bạn cũng cần chuyển nó cho hàm. Nhưng điều đó cũng cho phép bạn sử dụng WhereContains này cho nhiều trường hợp khác.

Sử dụng nó trông như thế này:

// Test is a class with two string properties `City` and `Region` 
var myList = new List<Test>{ 
    new Test() { City = "asdf", Region = "fdsa" }, 
    new Test() { City = "foo", Region = "bar" }, 
    new Test() { City = "bar", Region = "baz" } 
}; 

var myFilters = new List<string> { "asdf", "bar" }; 

myList.WhereContains(myFilters, x => x.City); // contains asdf/fdsa and bar/baz 
myList.WhereContains(myFilters, x => x.Region); // contains foo/bar 
+1

Đây là cách tốt hơn so với sử dụng sự phản chiếu ... +1 – Viru

+0

Tôi đã sử dụng để bỏ qua các phương pháp chung suy nghĩ về cấu trúc phức tạp của nó. tốt nhất. – Manoj

1

Bạn có thể sử dụng Reflection

public void MySelect(string column) 
{ 
    var result = myList.Where(s => myFilters.Contains(s.GetType().GetProperty(column))); 
} 
0

Là một giải pháp thay thế, bạn có thể sử dụng các phương pháp sau đây cho phép xác định một trong hai lĩnh vực lọc hoặc chức năng lọc:

var adresses = new List<Address>{ 
    new Address() { City = "ABC", Country = "USA" }, 
    new Address() { City = "BC", Country = "USA" }, 
    new Address() { City = "C", Country = "UK" } 
}; 
var filterValues = new List<string> { "B", "UK", "U" }; 
// 
var FilterContains = [email protected]((values, value) => values.Contains(value)); 
var FilterStartsWith = [email protected]((values, value) => values.Any(v => value.StartsWith(v))); 
// 
var AdressesByCity = [email protected](a => a.City); 
var adressesByCitiesContains = AdressesByCity(filterValues, FilterContains); // B->{ABC;USA},{BC;USA} 
var adressesByCitiesStartsWith = AdressesByCity(filterValues, FilterStartsWith);// B->{BC;USA} 
// 
var AdressesByCountry = [email protected](a => a.Country); 
var adressesByCountriesContains = AdressesByCountry(filterValues, FilterContains);//U,UK-> {C;UK} 
var adressesByCountriesStartsWith = AdressesByCountry(filterValues, FilterStartsWith); //U,UK->{ABC;USA},{BC;USA}{C;UK} 

Ở đây, phương pháp khuyến nông @Specify được thực hiện như sau:

public static class @SpecifyExtension { 
    public static Func<IEnumerable<V>, Func<IEnumerable<V>, V, bool>, IEnumerable<U>> @Specify<U, V>(this IEnumerable<U> source, Func<U, V> selector) { 
     return (values, predicate) => source.Where(x => predicate(values, selector(x))); 
    } 
    public static Func<IEnumerable<TValue>, TValue, bool> @Specify<TValue>(this IEnumerable<TValue> source, Func<IEnumerable<TValue>, TValue, bool> func) { 
     return func; // for Type-inference only 
    } 
} 
Các vấn đề liên quan