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