更換List.Contains在試圖拓寬了我的技能,我想學習如何改寫表達式。重寫表達與自定義的方法
目標:給出一個表達式,我想用自己的靜態方法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))
調用這個,我得到一個InvalidOperationException
期間Expression.Call
:
的類型沒有方法「InList中「MyNamespace.InListRewriter`1 [ MyNamespace.Foo]'與提供的參數兼容。
我甚至嘗試做一個新的InList中有一個非常通用的簽名:
public static bool InList(params object[] things) {...}
但還是得到了同樣的錯誤。我究竟做錯了什麼?我甚至想做甚麼?
代碼看起來OK。查看您作爲參數傳入的表達式的類型。它們是否匹配(Foo,列表)? –
usr
@usr實施丹尼爾的回答,發現後,我有了第二個問題,事實證明,我的第二個問題是,我不小心被引用'foo.SomeParam',而不是'foo',因此類型不匹配而我得到的錯誤。所以你也是對的。 – ean5533