使用字典作为过滤方法参数的动态 LINQ 函数
Dynamic LINQ function using dictionary as a Parameter to filter method
我是反射区的新手。我必须通过使用它的键和值来过滤具有字典的实体列表,如下所示
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")
动态使用表达式构建器作为参数传递给扩展方法。谢谢
这里似乎根本不需要使用表达式构建器,或者实际上不需要任何扩展方法(看起来您是在重新发明轮子)。像下面这样的东西应该适合你的需要:
var filteredPeople = people.Where(person => person.SecQuestions[key] == value);
如何确定 key
和 value
由您决定。它可以是方法参数或用户输入或其他任何东西。
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
如果您仅需要您比较的值是动态的,那么您可以让语言来完成繁重的工作:
public Expression BuildComparison(string key, string value)
{
return Expression<Func<Person, bool>> exp =
x => x.SecQuestions.Any(y => y.Key == key && y.Value == value);
}
如果我误解了您的要求,我们深表歉意。
我是反射区的新手。我必须通过使用它的键和值来过滤具有字典的实体列表,如下所示
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")
动态使用表达式构建器作为参数传递给扩展方法。谢谢
这里似乎根本不需要使用表达式构建器,或者实际上不需要任何扩展方法(看起来您是在重新发明轮子)。像下面这样的东西应该适合你的需要:
var filteredPeople = people.Where(person => person.SecQuestions[key] == value);
如何确定 key
和 value
由您决定。它可以是方法参数或用户输入或其他任何东西。
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
如果您仅需要您比较的值是动态的,那么您可以让语言来完成繁重的工作:
public Expression BuildComparison(string key, string value)
{
return Expression<Func<Person, bool>> exp =
x => x.SecQuestions.Any(y => y.Key == key && y.Value == value);
}
如果我误解了您的要求,我们深表歉意。