【发布时间】:2013-07-19 00:05:53
【问题描述】:
为了扩大我的技能,我正在尝试学习如何重写表达式。
目标:给定一个表达式,我想用调用我自己的静态方法InList 来替换List.Contains() 的实例。例如,以下两个表达式应该是等价的:
Expression<Func<Foo,bool>> expr1 = myRewriter.Rewrite(foo => fooList.Contains(foo));
Expression<Func<Foo,bool>> expr2 = foo => InList(foo, fooList);
我的尝试:我了解到使用custom ExpressionVisitor 是基于现有表达式创建新表达式的最佳方式。但是,我无法构建一个新的MethodCallExpression 来实际调用我的方法。这是我尝试过的:
public class InListRewriter<T> : ExpressionVisitor
{
public static bool InList(T target, List<T> source)
{
// this is my target method
return true;
}
public Expression<Func<T, bool>> Rewrite(Expression<Func<T, bool>> expression)
{
return Visit(expression) as Expression<Func<T,bool>>;
}
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.Method.GetParameters()[0]; // The thing being searched for
// Create new expression
var type = typeof (InListRewriter<T>);
var methodName = "InList";
var typeArguments = new Type[] { };
var arguments = new[] { Expression.Parameter(target.ParameterType, target.Name), sourceList };
var newExpression = Expression.Call(type, methodName, typeArguments, arguments);
return newExpression;
}
}
但是,当我通过new InListRewriter<Foo>().Rewrite(foo => fooList.Contains(foo)) 调用它时,我在Expression.Call 期间得到一个InvalidOperationException:
类型“MyNamespace.InListRewriter`1[MyNamespace.Foo]”上没有方法“InList”与提供的参数兼容。
我什至尝试用非常通用的签名制作一个新的 InList:
public static bool InList(params object[] things) {...}
但仍然收到相同的错误。我究竟做错了什么?我想做的事有可能吗?
【问题讨论】:
-
代码看起来没问题。查看您作为参数传入的表达式的类型。它们匹配 (Foo, List
) 吗? -
@usr 在执行丹尼尔的回答并发现我有第二个问题之后,原来我的第二个问题是我不小心引用了
foo.SomeParam而不是foo,因此类型不匹配和我得到的错误。所以你也是对的。
标签: c# expression