AFAIK BCL 对使用表达式的支持非常有限。恐怕您将不得不自己重写表达式以更改方法参数类型。
这并不难,但也不容易。基本上,您将克隆Expression(它是一棵树)的每个节点,但将根节点的数据类型设置为您的Func<TImplementation, bool>。
我会寻找一种不同的设计来实现相同的目标,但没有这种铸造要求 - 浏览表达式并不有趣。
更新我已经实现了一个功能,可以满足您的需求。我叫它CastParam:
public static Expression<Func<TOut, bool>> CastParam<TIn, TOut>(this Expression<Func<TIn, bool>> inExpr) {
if (inExpr.NodeType == ExpressionType.Lambda &&
inExpr.Parameters.Count > 0) {
var inP = inExpr.Parameters[0];
var outP = Expression.Parameter(typeof(TOut), inP.Name);
var outBody = inExpr.Body.ConvertAll(
expr => (expr is ParameterExpression) ? outP : expr);
return Expression.Lambda<Func<TOut,bool>>(
outBody,
new ParameterExpression[] { outP });
}
else {
throw new NotSupportedException();
}
}
它所做的只是重写表达式,用新类型替换旧的 ParamaterType。这是我的小测试:
class TInterface { public int IntVal; }
class TImplementation : TInterface { public int ImplVal; }
void Run ()
{
Expression<Func<TInterface, bool>> intExpr = (i => i.IntVal == 42);
Expression<Func<TImplementation, bool>> implExpr = intExpr.CastParam<TInterface, TImplementation> ();
Console.WriteLine ("{0} --> {1}", intExpr, implExpr);
var c = implExpr.Compile ();
Console.WriteLine (c.Invoke (new TImplementation { IntVal = 41, ImplVal = 42 }));
Console.WriteLine (c.Invoke (new TImplementation { IntVal = 42, ImplVal = 41 }));
}
正如预期的那样,它会打印:
假的
是的
代码依赖于我编写的Expression 重写器(自下而上重写表达式树):
public static Expression Rewrite(this Expression exp, Func<Expression, Expression> c) {
Expression clone = null;
switch (exp.NodeType) {
case ExpressionType.Equal: {
var x = exp as BinaryExpression;
clone = Expression.Equal(Rewrite(x.Left,c), Rewrite(x.Right,c), x.IsLiftedToNull, x.Method);
} break;
case ExpressionType.MemberAccess: {
var x = exp as MemberExpression;
clone = Expression.MakeMemberAccess(Rewrite(x.Expression,c), x.Member);
} break;
case ExpressionType.Constant: {
var x = exp as ConstantExpression;
clone = Expression.Constant(x.Value);
} break;
case ExpressionType.Parameter: {
var x = exp as ParameterExpression;
clone = Expression.Parameter(x.Type, x.Name);
} break;
default:
throw new NotImplementedException(exp.NodeType.ToString());
}
return c(clone);
}
重写器显然不完整,您需要完成它。