如何动态构建表达式c => c.workers.any(o => o.code =='XXX'|| c.name =='XXX')

时间:2017-06-02 08:46:46

标签: c# linq-to-entities expression

我学习如何构建像

这样的简单表达式
c=>c.code=='XXX';

我通过以下方法创建这些表达式:

public static Expression<Func<T, bool>> BuildStringEqualLambda(string propertyName, string propertyValue)
{
    ParameterExpression parameterExp = Expression.Parameter(typeof(T), "type");
    Expression propertyExp = parameterExp;
    foreach (var property in propertyName.Split('.'))
    {
        propertyExp = Expression.PropertyOrField(propertyExp, property);
    }
    Expression right = Expression.Constant(propertyValue);
    Expression e1 = Expression.Equal(propertyExp, right);
    return Expression.Lambda<Func<T, bool>>(e1, new ParameterExpression[] { parameterExp });
}

我想我可以构建表达式

o=>o.code=='XXX' || c.name=='XXX'

但我不知道如何构建方法Any。

由于

1 个答案:

答案 0 :(得分:1)

应该是这样的:

public static Expression<Func<T, bool>> BuildStringEqualLambda<T>(params Tuple<string, string>[] propertyNameValues)
{
    if (propertyNameValues == null || propertyNameValues.Length == 0)
    {
        throw new ArgumentException(nameof(propertyNameValues));
    }

    ParameterExpression parameterExp = Expression.Parameter(typeof(T), "type");

    Expression body = null;

    foreach (var propertyNameValue in propertyNameValues)
    {
        Expression propertyExp = parameterExp;

        foreach (var property in propertyNameValue.Item1.Split('.'))
        {
            propertyExp = Expression.PropertyOrField(propertyExp, property);
        }

        Expression right = Expression.Constant(propertyNameValue.Item2);
        Expression eq = Expression.Equal(propertyExp, right);

        body = body == null ? eq : Expression.OrElse(body, eq);
    }

    return Expression.Lambda<Func<T, bool>>(body, new ParameterExpression[] { parameterExp });
}

您可以使用一些有趣的LINQ和Aggregate来减少行数,但它可能是不可取的。

最后,您使用Expression.OrElse Expression.Or |!)并处理第一个元素案例。

使用它像:

var exp = BuildStringEqualLambda(
    Tuple.Create("prop1", "value1"),
    Tuple.Create("prop2", "value2"),
    Tuple.Create("prop3", "value3")
);

使用一些LINQ和Aggregate(对于那些在没有LINQing的情况下无法生存的人)(请注意,虽然我不会使用LINQed版本的代码......但这是相当的不可读...... Enumerable.Aggregate是可怕的&#34;):

public static Expression<Func<T, bool>> BuildStringEqualLambda<T>(params Tuple<string, string>[] propertyNameValues)
{
    if (propertyNameValues == null || propertyNameValues.Length == 0)
    {
        throw new ArgumentException(nameof(propertyNameValues));
    }

    ParameterExpression parameterExp = Expression.Parameter(typeof(T), "type");

    Expression body = propertyNameValues
        .Select(x => BuildEqualityExpression<T>(parameterExp, x.Item1, x.Item2))
        .Aggregate((acc, x) => Expression.OrElse(acc, x));

    return Expression.Lambda<Func<T, bool>>(body, new ParameterExpression[] { parameterExp });
}

private static Expression BuildEqualityExpression<T>(ParameterExpression parameterExp, string propertyName, string propertyValue)
{
    Expression propertyExp = propertyName
        .Split('.')
        .Aggregate((Expression)parameterExp, (acc, x) => Expression.PropertyOrField(acc, x));

    Expression right = Expression.Constant(propertyValue);
    Expression eq = Expression.Equal(propertyExp, right);
    return eq;
}