如何演绎Expression <func <t1,bool>&gt;到表达式<func <t2,bool>&gt;?

时间:2018-02-12 22:11:46

标签: c#

如何将Expression<Func<T1,bool>>投射到Expression<Func<T2,bool>>请注意,T1和T2都有相同的界面。

1 个答案:

答案 0 :(得分:0)

这是一个示例解决方案,不能在真实代码中使用

如果childExpression使用的不是Base属性,则会中断。如果您有许多参数,这将会中断(演示访问者以更简单的方式实现)。这可能会在很多情况下中断,它只能用于解释目的。

现在,解释

可以通过访问Expression并将参数替换为新参数来完成此任务:

class Base
{
    public string Name { get; set; }
}

class Child : Base { }

我们假设您Expression Child只使用.Name

var childExpression = (Expression<Func<Child, bool>>)(e => e.Name == "works!");

我们可以为Base类型创建一个新参数,而不是Child

var newParameter = Expression.Parameter(typeof(Base));

提取旧体:

var newBody = childExpression.Body;

嗯,这有一个问题:旧机身正在使用旧参数里面的参数,我们需要用新的参数替换它。

class ParameterReplacer : ExpressionVisitor
{
    private ParameterExpression _newParameter;

    public ParameterReplacer(ParameterExpression newParameter)
    {
        _newParameter = newParameter;
    }

    protected override Expression VisitParameter(ParameterExpression node)
    {
        return _newParameter; // forget about the old one, return the new
    }
}

那么我们可以通过适当的参考来获得我们的身体:

var body = new ParameterReplacer(newParameter).Visit(childExpression.Body);

将结果合并为一个完美类型的Expression<Func<Base, bool>>

var expressionForBase = Expression.Lambda<Func<Base, bool>>(body, newParameter);

当然,它有效:

var predicate = expressionForBase.Compile().Invoke(new Base
{
    Name = "works!"
}); // true!