2017-06-02 3 views
1

どのようにして式c => c.workers.any(o => o.code == 'XXX' || c.name == 'XXX')を動的に構築できますか

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' 

を構築することができると思うしかし、私は、任意の方法を構築することができるのか分かりません。

おかげ

+0

見https://stackoverflow.com/questions/34730432/how-do-i-build-expression-call-for-を取りますany-method-with-generic-parameter –

答えて

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 }); 
} 

おそらく、行の数を減らすためにAggregateでいくつかの面白いLINQを使用することができますが、それはundebuggableだろう。最後に

あなたがExpression.OrElseを使う(|あるないExpression.Or!)、あなたが最初の要素のケースを扱います。

のようにそれを使用します。

いくつかのLINQを使用して
var exp = BuildStringEqualLambda(
    Tuple.Create("prop1", "value1"), 
    Tuple.Create("prop2", "value2"), 
    Tuple.Create("prop3", "value3") 
); 

Aggregate(すべてをリンチンなしでは生きられない人のために)(私が今までのコードのLINQedバージョンを使用していないだろうしながら、ということに注意してください。.. 。それは)Enumerable.Aggregateは "ひどい" です...かなり読めないです:

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; 
} 
関連する問題