Adding to Lambda Expression and work with Entity Framework

你说的曾经没有我的故事 提交于 2019-12-05 13:26:58

Given two "selector" expressions, you've to take the bindings from their MemberInitExpression and create a new expression using all the bindings. But this expression isn't going to work, since it uses two different parameter expressions for one single parameter. We need to fix that too.

Given...

Expression<Func<TSource, TResult>> left = ... // columns
Expression<Func<TSource, TResult>> right = ... // more columns

...take the bindings...

var leftInit = left.Body as MemberInitExpression;
var rightInit = right.Body as MemberInitExpression;

var bindings = leftInit.Bindings.Concat(rightInit.Bindings);

...create a new expression...

var result = Expression.Lambda<Func<TSource, TResult>>(
    Expression.MemberInit(Expression.New(typeof(TResult)), bindings), ???);

...BUT, need single parameter...

var binder = new ParameterBinder(left.Parameters[0], right.Parameters[0]);
var bindings = binder.Visit(leftInit.Bindings.Concat(rightInit.Bindings));

// now, just use right.Parameters[0] as parameter...

And, replacing parameters works well using an expression visitor:

class ParameterBinder : ExpressionVisitor
{
    readonly ParameterExpression parameter;
    readonly Expression replacement;

    public ParameterBinder(ParameterExpression parameter, Expression replacement)
    {
        this.parameter = parameter;
        this.replacement = replacement;
    }

    protected override Expression VisitParameter(ParameterExpression node)
    {
        if (node == parameter)
            return replacement;

        return base.VisitParameter(node);
    }
}

Abstracting this plumbing stuff works quite well. In fact, you can just use an existing library (spoiler: I'm the author), which should lead to something like that:

var merged = columns.Apply(moreColumns);
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!