Нулевая проверка по статистическому выражению - PullRequest
0 голосов
/ 08 января 2019

У меня есть помощник по выражению, помогающий получить значения из иерархии объектов

   public static Func<T, object> GetMemberExpressionFunc<T>(string expressionString)
   {
     if (string.IsNullOrEmpty(expressionString))
     {
         throw new InvalidOperationException("invalid Expression");
     }

     var parameter = Expression.Parameter(typeof(T));
     Expression memberExpression = parameter;
     var tokens = expressionString.Split('.');
     memberExpression = tokens.Aggregate(memberExpression, Expression.PropertyOrField);

     var convertExpression = Expression.Convert(memberExpression, typeof(object));
     return Expression.Lambda<Func<T, object>>(convertExpression, parameter)
                        .Compile();

    }

Использование

public class A
{
        public B BObj { get; set; }
}

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

}

 static void Main(string[] args)
 {
   var obj = new A {BObj = new B {Name ="Test"}};
   var obj2 = new A ();

   var exp = ExpressionHelper.GetMemberExpressionFunc<A>("BObj.Name");

  var test1 =  exp(obj);// test1 is "Test"

  var test2 = exp(obj2); //throws because BObj is null
}

Я хочу, чтобы выражение возвращало значение NULL, если какое-либо свойство в иерархии имеет значение NULL, а не выбрасывает исключение. Можно ли сделать это в агрегированном выражении?

1 Ответ

0 голосов
/ 09 января 2019

C # null условный оператор ?. был бы очень полезен в этом случае. К сожалению, он все еще не поддерживается в деревьях выражений, поэтому один из способов достижения цели - динамически создать эквивалент ручных нулевых проверок в будущем:

x => x != null && x.Prop1 != null && x.Prop1.Prop2 != null ... ? (object)x.Prop1.Prop2...PropN : null

Поскольку вам нужно было бы агрегировать как выражение доступа к члену, так и условие для использования в конечном Expression.Condition, метод Aggregate не годится - выполнение агрегации со старым добрым циклом foreach выглядит более подходящим, например, вот так:

var parameter = Expression.Parameter(typeof(T));

var nullConst = Expression.Constant(null);
Expression source = parameter, condition = null;
foreach (var memberName in expressionString.Split('.'))
{
    var notNull = Expression.NotEqual(source, nullConst);
    condition = condition != null ? Expression.AndAlso(condition, notNull) : notNull;
    source = Expression.PropertyOrField(source, memberName);
}
source = Expression.Convert(source, typeof(object));
var body = Expression.Condition(condition, source, nullConst);

return Expression.Lambda<Func<T, object>>(body, parameter)
                   .Compile();
...