Проверьте, существуют ли родительские объекты

Я использую много данных базы данных в моем проекте, который экспортируется в разные классы. Например, у меня есть

transaction.Layout.Multimedia.Images.first();

Проблема в том, что эти свойства не обязательно доступны.

Таким образом, возможно, что transaction.Layout Нуль, возможно, что transaction.Layout.Multimedia является нулевым, и так далее.

В настоящее время я использую это для каждого свойства:

if (transaction.Layout != null)
{
    if (transaction.Layout.Multimedia != null)
    {
        if (transaction.Layout.Multimedia.Images != null)
        {
            if (transaction.Layout.Multimedia.Images.count > 0)
            {
                var img = transaction.Layout.Multimedia.Images.first();
            }
        }
    }
}

Мне было интересно, есть ли лучший способ, которым я могу проверить все родительские классы, чтобы убедиться, что нужное мне свойство доступно. Это не единственные объекты, которые я использую, есть и другие с совершенно другими именами.

заранее спасибо

3 ответа

Решение

Нет, пока нет. В новой версии.NET ( Roslyn) есть распространяющий оператор Null.

Тогда вы могли бы сделать:

if (transaction?.Layout?.Multimedia?.Image?.count > 0)
{
    var img = transaction.Layout.Multimedia.Images.first();
}

На данный момент мы застряли с этим. Вы можете минимизировать количество необходимых строк, объединяя проверки, например так:

if ( transaction.Layout != null
     && transaction.Layout.Multimedia != null
     && transaction.Layout.Multimedia.Images != null
     && transaction.Layout.Multimedia.Images.count > 0
   )
{
    var img = transaction.Layout.Multimedia.Images.first();
}

Больше нечего делать.

Вы можете попробовать использовать Возможно монаду. Более подробное описание приведено в Цепных нулевых проверках и Монаде Возможно

With а также If методы расширения позволят вам написать:

var img = transaction.With(x => x.Layout)
                     .With(x => x.Multimedia)    
                     .With(x => x.Images)
                     .If(x => x.count > 0))
                     .With(x => x.first());

With Метод выглядит так:

public static TResult With<TInput, TResult>(this TInput o, Func<TInput, TResult> evaluator)
  where TResult : class where TInput : class
{
  if (o == null) return null;
  return evaluator(o);
}

If метод:

public static TInput If<TInput>(this TInput o, Func<TInput, bool> evaluator) 
  where TInput : class
{
  if (o == null) return null;
  return evaluator(o) ? o : null;
}

Это немного OT, но теоретически вы можете использовать методы расширения для достижения более простого синтаксиса:

public static class GetterExtensions {
  public static LayoutClass GetLayout(this TransactionClass transaction) {
    if (transaction == null)
      return null;
    else
      return transaction.Layout;
  }
  public static MultimediaClass GetMultimedia(this LayoutClass layout) {
    if (layout == null)
       return null;
    else
       return layout.Multimedia;
  }
  public static ImagesClass GetImages(this MultimediaClass multimedia) {
    if (multimedia == null)
       return null;
    else
       return multimedia.Images;
  }
  public static int? GetCount(this ImagesClass images) {
    if (images == null)
       return null;
    else
       return images.count;
  }
}

(Куда LayoutClass, MultimediaClass и т. д. являются типами соответствующих свойств).

Имея это, вы могли бы написать

if (transaction.GetLayout().GetMultimedia().GetImages().GetCount() > 0)
  // ...

Это решение использует тот факт, что методы расширения могут быть вызваны на null объекты без исключения. Они просто получают null как их this Параметр в этом случае. Также не int? тип возврата (Nullable<int>) из GetCount() метод, который позволяет вернуть null для целочисленного свойства.

Но если у вас много объектов (со многими свойствами), это решение, вероятно, нецелесообразно и требует много дополнительных усилий по обслуживанию. Кроме того, написание GetLayout() вместо просто Layout все еще менее элегантно.

Другие вопросы по тегам