动态LINQ函数使用字典作为参数来过滤方法

时间:2015-10-02 06:57:35

标签: c# linq dictionary func

我是反射区的新手。我必须使用它的键和值来过滤具有字典的实体列表,如下所示

public class Person
{
    public string Name { get; set; }
    public Dictionary<string,string> SecQuestions { get; set; }
}

以下扩展名在dll中可用,无法修改

public static class extensions
{
    public static List<Person> FilterMe(this List<Person> Persons, Func<Person,bool> predicate)
    {
        // Logic to filter the persion list
        return Persons;
    }
}

因此我必须使用下面的代码

来调用上面的方法
persons.FilterMe(xy => xy.SecQuestions.Any(x => x.Key == "PlaceOfBirth" && x.Value == "Madurai"));

我需要知道如何创建

xy => xy.SecQuestions
    .Any(x => x.Key == "PlaceOfBirth" && x.Value == "Madurai")

动态地使用表达式构建器作为参数传递给扩展方法。感谢

3 个答案:

答案 0 :(得分:1)

var personP = Expression.Parameter(typeof(Person), "xy");            // Creates xy Parameter
var SecQuestionsProp = Expression.Property(personP, "SecQuestions"); // Creates xy.SecQuestions

var anyMethodInfo = typeof(Enumerable).GetMethods(System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public)
    .Where(m => m.Name == "Any" && m.IsGenericMethod) // Search for Any methods...
    .Select(m => new {
                        Method = m,
                        Params = m.GetParameters(),
                        Args = m.GetGenericArguments()
                     })
    .Where(x => x.Args.Length == 1 
        && x.Params.Length == 2 
        && x.Params[0].ParameterType == typeof(IEnumerable<>).MakeGenericType(x.Args)
        && x.Params[1].ParameterType == typeof(Func<,>).MakeGenericType(new Type[] { x.Args.First(), typeof(bool) })) // Get the one defined as Any<TSource>(IEnumerable<TSource>, Func<TSource, bool>)
    .Select(x => x.Method)
    .First();

var keyValuePairP = Expression.Parameter(typeof(KeyValuePair<string, string>), "x"); // Creates x Parameter
var KeyProp = Expression.Property(keyValuePairP, "Key");                             // Creates x.Key
var keyComparisonValue = Expression.Constant("PlaceOfBirth");                        // Creates the value that will be compared to x.Key
var keyComparison = Expression.Equal(KeyProp, keyComparisonValue);                   // Creates the comparison (x.Key == "PlaceOfBirth")

var ValueProp = Expression.Property(keyValuePairP, "Value");                         // Creates x.Value
var valueComparisonValue = Expression.Constant("Madurai");                           // Creates the value that will be compared to x.Value
var valueComparison = Expression.Equal(ValueProp, valueComparisonValue);             // Creates the comparison (x.Value == "Madurai")

var anyPredicate = Expression.Lambda(Expression.AndAlso(keyComparison, valueComparison), new ParameterExpression[] { keyValuePairP }); // Creates x => x.Key == "PlaceOfBirth" && x.Value == "Madurai"

var filterMeMethod = Expression.Lambda<Func<Person, bool>>
    (Expression.Call(anyMethodInfo.MakeGenericMethod(new Type[] { typeof(KeyValuePair<string, string>) })
                    , new Expression[] { SecQuestionsProp, anyPredicate })
     , personP);  //Creates xy => xy.SecQuestions.Any(x => x.Key == "PlaceOfBirth" && x.Value == "Madurai")

var r1 = persons.FilterMe(filterMeMethod.Compile());  // Calls FilterMe with xy => xy.SecQuestions.Any(x => x.Key == "PlaceOfBirth" && x.Value == "Madurai") as parameter

答案 1 :(得分:0)

在这里似乎没有任何需要使用表达式构建器,或者实际上任何扩展方法(看起来你正在重新发明轮子)。以下内容应符合您的需求:

var filteredPeople = people.Where(person => person.SecQuestions[key] == value);

keyvalue如何确定取决于您。它可以是方法参数或用户输入等等。

答案 2 :(得分:0)

如果您需要您要比较的值是动态的,那么您可以让语言变得繁重:

public Expression BuildComparison(string key, string value)
{
    return Expression<Func<Person, bool>> exp = 
                 x => x.SecQuestions.Any(y => y.Key == key && y.Value == value);
}

如果我误解了你的要求,请道歉。