linq表达式作为参数

时间:2016-02-11 11:21:33

标签: c# linq

我必须像这样查询集合:

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(???);
}

myListObservableCollectionmyFiltersList<string>

3 个答案:

答案 0 :(得分:10)

将此扩展方法放在静态类中:

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之类的简单lamba传递给它。

由于它完全是通用的而不是特定于您的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

答案 1 :(得分:1)

您可以使用反射

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

答案 2 :(得分:0)

作为替代解决方案,您可以使用以下方法,该方法允许指定过滤器字段或过滤器功能:

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
    }
}