【发布时间】:2021-02-03 15:09:01
【问题描述】:
我正在尝试在 C# 中创建一个表达式树来动态表示以下嵌套的 lambda...
item => selectorList.Any(selector => terms.Any(sTerm => selector.Contains(sTerm))
地点:
- 'item' 是泛型类型 T
- 'selectorList' 的类型为 IEnumerable
>> - 'terms' 是 IEnumerable 类型
经过大量工作,我已经到了这里——但现在我正在努力把它做好。我缺少对嵌套时如何将 ParameterExpression 用作解析值的一些基本理解。
public static Expression<Func<T, bool>> CreateWhereAnyContainsLambaExpression<T>(IEnumerable<string> terms, params Expression<Func<T, String>>[] selectorList)
{
// Create ParameterExpressions
ParameterExpression qi = Expression.Parameter(typeof(T), "qi");
ParameterExpression selector = Expression.Parameter(typeof(Expression<Func<T, String>>), "selector");
ParameterExpression sTerm = Expression.Parameter(typeof(string), "sTerm");
// Create ConstantExpressions
ConstantExpression termsConstant = Expression.Constant(terms);
ConstantExpression selectorListConstant = Expression.Constant(selectorList);
// Get MethodInfo
MethodInfo selectorListAny = typeof(Enumerable).GetMethods().Where(m => m.Name == "Any").First(m => m.GetParameters().Count() == 2).MakeGenericMethod(typeof(Expression<Func<T, string>>));
MethodInfo termsAny = typeof(Enumerable).GetMethods().Where(m => m.Name == "Any").First(m => m.GetParameters().Count() == 2).MakeGenericMethod(typeof(string));
MethodInfo selectorContains = typeof(string).GetMethod("Contains", new[] { typeof(string) });
// Build the Expression from inside to out....
// selector.Contains(sTerm)
var expSelectorContains = Expression.Call(selector, selectorContains, sTerm);
// sTerm => ...expSelectorContains...
var sTermLambda = Expression.Lambda<Func<string, bool>>(expSelectorContains, sTerm);
// terms.Any(...sTermLambda...)
var expTermsAny = Expression.Call(termsConstant, termsAny, sTermLambda);
// selector => ...expTermsAny...
var selectorLambda = Expression.Lambda<Func<Expression<Func<T, string>>, bool>>(expTermsAny, selector);
// selectorList.Any(...selectorLambda...)
var expSelectorListAny = Expression.Call(selectorListConstant, selectorListAny, selectorLambda);
// item => ...expSelectorListAny...
var lambda = Expression.Lambda<Func<T, bool>>(expSelectorListAny, qi);
return lambda;
}
失败在行
// selector.Contains(sTerm)
var expSelectorContains = Expression.Call(selector, selectorContains, sTerm);
我在哪里得到异常
System.ArgumentException : Method 'Boolean Contains(System.String)' declared on type 'System.String' cannot be called with instance of type 'System.Linq.Expressions.Expression`1[System.Func`2[TestObject,System.String]]'
鉴于 sTerm 是一个参数表达式,我该如何将其解析后的表示传递给 Contains 方法?
【问题讨论】:
-
在问题中使用“挑战”之类的词的问题在于,根据定义,您不是判断手头任务复杂程度的合适人选,因为您不知道该怎么做它。
-
“复杂”可能会更好,但老实说,我怀疑这与罗斯林家伙必须想出的东西相近。
-
您的问题的一部分我没有关注:
selectorList是IEnumerable<Expression<Func<T,string>>>,但随后您在其中一个元素上调用.Contains。Func<T,string>没有.Contains方法。你能给出这个方法被调用的例外情况,所以我可以看到一些示例输入吗? -
我最终被这个问题吞噬了。下面我注意到我将该参数类型切换为
string以解决您指出的问题 -.Contains不是针对 'Func' 的有效方法。我想要做的是传入一个选择器(即 x=>x.MyProperty) - 实际上它是它们的列表,并且可以将其解析为MyProperty值是什么对象(它将是string)。然后用它来反对Contains。那有意义吗?我会尝试用更多的上下文来更新我的问题。
标签: c# lambda expression-trees