将2参数表达式转换为1参数表达式

时间:2018-09-28 02:25:45

标签: c# entity-framework linq functional-programming

假设我有一个Expression<Func<Arg1,Arg2,ReturnType>>,如何将其转换为Expression<Func<Arg1,ReturnType>>

我已经定义了一个Expression<Func<Individual, Record, bool>>,如果允许个人查看记录,则该返回true。我想在个人或记录的DbContext上的Where子句中使用此表达式。示例:

Expression<Func<Individual,Record,bool>> expression = GetFilterExpression();

// Get All the records that an individual can review...
Individual ind = SomeIndividual();
Expression<Func<Individual,bool>> canBeViewedBy = Utility.ReplaceParameter(expression, 0, ind);
List<Record> records = _context.Records.Where(canBeViewedBy).ToList();

// Get All the individuals that can review the record...
Record record = SomeRecord();
Expression<Func<Record,bool>> canView = Utility.ReplaceParameter(expression, 1, record);
List<Individual> individuals = _context.Individuals.Where(canView).ToList();

在我的实际应用程序中,我有一个CanIndividualViewRecordSpecification,当前会生成一个Expression<Func<Record,bool>>。我希望它也能够生成Expression<Func<Individual,bool>>,而不必多次定义过滤器。

1 个答案:

答案 0 :(得分:1)

我最终自己解决了。

public static class ExpressionHelpers
{
    public static Expression<Func<TArg2, TReturn>> ReplaceParamter<TArg1, TArg2, TReturn>(this Expression<Func<TArg1, TArg2, TReturn>> source, TArg1 arg1)
    {
        var t1Param = Expression.Constant(arg1);
        var t2Param = Expression.Parameter(typeof(TArg2));
        var body = source.Body
                    .ReplaceParameter(source.Parameters[0], t1Param)
                    .ReplaceParameter(source.Parameters[1], t2Param);
        return Expression.Lambda<Func<TArg2, TReturn>>(body, t2Param);
    }

    public static Expression<Func<TArg1, TReturn>> ReplaceParamter<TArg1, TArg2, TReturn>(this Expression<Func<TArg1, TArg2, TReturn>> source, TArg2 arg2)
    {
        var t1Param = Expression.Parameter(typeof(TArg1));
        var t2Param = Expression.Constant(arg2);
        var body = source.Body
                    .ReplaceParameter(source.Parameters[0], t1Param)
                    .ReplaceParameter(source.Parameters[1], t2Param);
        return Expression.Lambda<Func<TArg1, TReturn>>(body, t1Param);
    }


    public static Expression ReplaceParameter(this Expression expression,
        ParameterExpression toReplace,
        Expression newExpression)
    {
        return new ParameterReplaceVisitor(toReplace, newExpression)
            .Visit(expression);
    }
}


public class ParameterReplaceVisitor : ExpressionVisitor
{
    private ParameterExpression from;
    private Expression to;
    public ParameterReplaceVisitor(ParameterExpression from, Expression to)
    {
        this.from = from;
        this.to = to;
    }
    protected override Expression VisitParameter(ParameterExpression node)
    {
        return node == from ? to : base.VisitParameter(node);
    }
}

示例:

Expression<Func<Individual,Record,bool>> expression = GetFilterExpression();

// Get All the records that an individual can review...
Individual ind = SomeIndividual();
Expression<Func<Record,bool>> canBeViewedBy = expression.ReplaceParameter(ind);
List<Record> records = _context.Records.Where(canBeViewedBy).ToList();

// Get All the individuals that can review the record...
Record record = SomeRecord();
Expression<Func<Individual,bool>> canView = expression.ReplaceParameter(record);
List<Individual> individuals = _context.Individuals.Where(canView).ToList();