转换表达式<func <tderived,out =“”tresult =“”>&gt;表达式<func <tbase,out =“”tresult =“”>&gt;

时间:2015-07-01 12:56:21

标签: c# entity-framework lambda expression-trees

所有都在标题中说,更确切地说,我正在寻找转换

的方法

Expression<Func<TDerived, out bool>>Expression<Func<TBase, out bool>>

TDerived来自TBase。

我怎样才能做到这一点?

2 个答案:

答案 0 :(得分:1)

给出像这样的Expression替换者:

using System;
using System.Collections.Generic;
using System.Linq.Expressions;

// A simple expression visitor to replace some nodes of an expression 
// with some other nodes. Can be used with anything, not only with
// ParameterExpression
public class SimpleExpressionReplacer : ExpressionVisitor
{
    public readonly Dictionary<Expression, Expression> Replaces;

    public SimpleExpressionReplacer(Expression from, Expression to)
    {
        Replaces = new Dictionary<Expression, Expression> { { from, to } };
    }

    public SimpleExpressionReplacer(Dictionary<Expression, Expression> replaces)
    {
        // Note that we should really clone from and to... But we will
        // ignore this!
        Replaces = replaces;
    }

    public SimpleExpressionReplacer(IEnumerable<Expression> from, IEnumerable<Expression> to)
    {
        Replaces = new Dictionary<Expression, Expression>();

        using (var enu1 = from.GetEnumerator())
        using (var enu2 = to.GetEnumerator())
        {
            while (true)
            {
                bool res1 = enu1.MoveNext();
                bool res2 = enu2.MoveNext();

                if (!res1 || !res2)
                {
                    if (!res1 && !res2)
                    {
                        break;
                    }

                    if (!res1)
                    {
                        throw new ArgumentException("from shorter");
                    }

                    throw new ArgumentException("to shorter");
                }

                Replaces.Add(enu1.Current, enu2.Current);
            }
        }
    }

    public override Expression Visit(Expression node)
    {
        Expression to;

        if (node != null && Replaces.TryGetValue(node, out to))
        {
            return base.Visit(to);
        }

        return base.Visit(node);
    }
}

现在我们可以,

public class Base
{
    public int ValueBase { get; set; }
}

public class Derived : Base
{
    public int ValueDerived { get; set; }
}

Expression<Func<Derived, bool>> exp = x => x.ValueBase == 0;

然后

ParameterExpression parOld = exp.Parameters[0];
ParameterExpression parNew = Expression.Parameter(typeof(Base));

// Replace the parOld with the parNew
Expression body2 = new SimpleExpressionReplacer(parOld, parNew).Visit(exp.Body);

// Note that we have to rebuild the Expression.Lambda<>
Expression<Func<Base, bool>> expNew = Expression.Lambda<Func<Base, bool>>(body2, parNew);

这会产生一个

Expression<Func<Base, bool>> exp = x => x.ValueBase == 0;

请注意,如果您想改为:

Expression<Func<Derived, bool>> exp = x => x.ValueDerived == 0;

Expression<Func<Base, bool>> exp = x => ((Derived)x).ValueDerived == 0;

然后你需要这样的东西:

ParameterExpression parOld = exp.Parameters[0];
ParameterExpression parNew = Expression.Parameter(typeof(Base));
UnaryExpression convert = Expression.Convert(parNew, typeof(Derived));

Expression body2 = new SimpleExpressionReplacer(parOld, convert).Visit(exp.Body);
Expression<Func<Base, bool>> expNew = Expression.Lambda<Func<Base, bool>>(body2, parNew);

答案 1 :(得分:0)

你需要包装内部表达式。像

这样的东西
var argument = Expression.Parameter(typeof(TDerived));

Expression.Lambda<Func<TDerived, bool>>
(
  Expression.Invoke(innerExpression, argument),
  argument
);

当然,根据方向,您可能需要对innerExpression的参数进行显式强制转换 - 这很简单,只需使用Expression.Cast

修改

为了适应您的编辑,倒置的变体:

var argument = Expression.Parameter(typeof(TBase));

Expression.Lambda<Func<TBase, bool>>
(
  Expression.Invoke(innerExpression, Expression.Convert(argument, typeof(TDerived))),
  argument
);

请注意,这显然仅在参数的运行时类型派生自TDerived时才有效。