另一个Linq问题=)
所以我有一个可以编码的特定界面和一个具有此签名的表达式
Expression<Func<TInterface, bool>>
在某些时候我需要使用该表达式,但它需要看起来像这样
Expression<Func<TImplementaion, bool>>
我试过这个
Expression<Func<TImplementation, bool>> expression = x => myExpression.Compile().Invoke(x);
虽然这编译表达式在翻译中丢失了 有任何想法吗? 感谢
答案 0 :(得分:3)
AFAIK BCL对使用Expressions的支持非常有限。我担心您将不得不自己重写表达式以更改方法参数类型。
这并不难,但也不容易。基本上,您将克隆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 }));
}
正如所料,它打印:
False True
代码依赖于我编写的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);
}
重写者显然是不完整的,你需要完成它。