C# 重写表达式以用自定义方法替换List.Contains
为了扩大我的技能范围,我正在努力学习如何重写表达式 目标:给定一个表达式,我想用调用自己的静态方法C# 重写表达式以用自定义方法替换List.Contains,c#,expression,C#,Expression,为了扩大我的技能范围,我正在努力学习如何重写表达式 目标:给定一个表达式,我想用调用自己的静态方法InList替换List.Contains()的实例。例如,以下两个表达式应等效: Expression<Func<Foo,bool>> expr1 = myRewriter.Rewrite(foo => fooList.Contains(foo)); Expression<Func<Foo,bool>> expr2 = foo => In
InList
替换List.Contains()
的实例。例如,以下两个表达式应等效:
Expression<Func<Foo,bool>> expr1 = myRewriter.Rewrite(foo => fooList.Contains(foo));
Expression<Func<Foo,bool>> expr2 = foo => InList(foo, fooList);
但是,当我通过new InListRewriter().Rewrite(foo=>whoolist.Contains(foo))
调用此函数时,在表达式调用期间,我会得到一个InvalidOperationException
:
类型“MyNamespace.InListRewriter`1[MyNamespace.Foo]”上的方法“InList”与提供的参数不兼容
我甚至尝试用一个非常通用的签名创建一个新的InList:
public static bool InList(params object[] things) {...}
但仍然收到相同的错误。我做错了什么?我想做的是可能的吗?您的代码有一个大问题:它传递的参数不正确,特别是第一个参数
您需要使用实际参数,而不是Expression.Parameter(target.ParameterType,target.Name)
:节点.Arguments[0]
此外,我建议您使用不同的表达式重载。Call
:使用MethodInfo
的重载
最终的代码如下所示:
protected override Expression VisitMethodCall(MethodCallExpression node)
{
// Only rewrite List.Contains()
if (!node.Method.Name.Equals("Contains",
StringComparison.InvariantCultureIgnoreCase))
return base.VisitMethodCall(node);
// Extract parameters from original expression
var sourceList = node.Object; // The list being searched
var target = node.Arguments[0]; // The thing being searched for
var newMethod = GetType().GetMethod("InList",
BindingFlags.Static | BindingFlags.Public);
// Create new expression
var newExpression = Expression.Call(newMethod, target, sourceList);
return newExpression;
}
代码看起来不错。查看作为参数传递的表达式所具有的类型。它们是否匹配(Foo,List)?@usr在实现Daniel的答案并发现我有第二个问题后,我的第二个问题是我无意中引用了
Foo.SomeParam
,而不是Foo
,因此出现了类型不匹配和错误。所以你也是对的。是的,但是表达式.Call
调用仍然应该通过,因为类型匹配。@usr:我不认为OP得到的异常来自他显示的代码。当我执行他的代码时,我得到了一个完全不同的代码,它更符合他的代码的实际问题:InvalidOperationException:从范围“”引用的类型为“UserQuery+Foo”的变量“item”,但它没有定义。修复了方法调用表达式的第一个参数的问题,删除了该错误,代码正常工作。在所有帐户上都正确。我更改了我的访问者以匹配您的访问者,并开始收到不同的错误。然而,将代码提取到一个更简单的文件中可以使其正确运行,因此在重写器之外,我的代码还有其他问题。我最终会弄明白的。不管怎样,你肯定回答了我的问题,谢谢。
protected override Expression VisitMethodCall(MethodCallExpression node)
{
// Only rewrite List.Contains()
if (!node.Method.Name.Equals("Contains",
StringComparison.InvariantCultureIgnoreCase))
return base.VisitMethodCall(node);
// Extract parameters from original expression
var sourceList = node.Object; // The list being searched
var target = node.Arguments[0]; // The thing being searched for
var newMethod = GetType().GetMethod("InList",
BindingFlags.Static | BindingFlags.Public);
// Create new expression
var newExpression = Expression.Call(newMethod, target, sourceList);
return newExpression;
}