转换表达式<func <tinterface,bool =“”>&gt;到表达式<func <timplementation,bool =“”>&gt; </func <timplementation,> </func <tinterface,>

时间:2009-11-19 19:14:43

标签: linq

另一个Linq问题=)

所以我有一个可以编码的特定界面和一个具有此签名的表达式

 Expression<Func<TInterface, bool>>

在某些时候我需要使用该表达式,但它需要看起来像这样

 Expression<Func<TImplementaion, bool>>

我试过这个

Expression<Func<TImplementation, bool>> expression = x => myExpression.Compile().Invoke(x);

虽然这编译表达式在翻译中丢失了 有任何想法吗? 感谢

1 个答案:

答案 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);
}

重写者显然是不完整的,你需要完成它。