作为参数的 LINQ 表达式
本文关键字:LINQ 表达式 参数 | 更新日期: 2023-09-27 18:34:20
我必须像这样查询集合:
myList.Where(s => myFilters.Contains(s.CountryCode))
s.CountryCode
上面是一个例子。我想让它变速并调用不同的列,如下所示:
myList.Where(s => myFilters.Contains(s.City))
myList.Where(s => myFilters.Contains(s.Region))
myList.Where(s => myFilters.Contains(s.Zipcode))
所以我想定义列表达式是参数的函数。这种功能的签名是什么?
public void MySelect( ??? )
{
myList.Where(s => myFilters.Contains(???);
}
myList
是ObservableCollection
,myFilters
是List<string>
将此扩展方法放在静态类中:
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)));
}
此扩展方法的工作方式是它接受一个 lambda 函数,该函数在给定您类型的对象的情况下解析属性。所以你只需要把一个简单的兰巴像x => x.City
传递给它。
由于它是完全通用的,而不是特定于您的一个myFilters
集合,因此您还需要将其传递给函数。但这允许您将此WhereContains
用于许多其他情况。
使用它看起来像这样:
// 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
您可以使用反射
public void MySelect(string column)
{
var result = myList.Where(s => myFilters.Contains(s.GetType().GetProperty(column)));
}
作为替代解决方案,您可以使用以下方法,该方法允许指定过滤器字段或过滤器功能:
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 = filterValues.@Specify((values, value) => values.Contains(value));
var FilterStartsWith = filterValues.@Specify((values, value) => values.Any(v => value.StartsWith(v)));
//
var AdressesByCity = adresses.@Specify(a => a.City);
var adressesByCitiesContains = AdressesByCity(filterValues, FilterContains); // B->{ABC;USA},{BC;USA}
var adressesByCitiesStartsWith = AdressesByCity(filterValues, FilterStartsWith);// B->{BC;USA}
//
var AdressesByCountry = adresses.@Specify(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}
这里@Specify
扩展方法
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
}
}