Глубокая проверка нуля, есть ли лучший способ? - PullRequest
128 голосов
/ 17 января 2010

Примечание: Этот вопрос задавался до введения оператора .? в C # 6 / Visual Studio 2015 .

Мы все были там, у нас есть какое-то глубокое свойство, например cake.frosting.berries.loader, которое нам нужно проверить, имеет ли оно значение null, поэтому нет никаких исключений. Это можно сделать с помощью короткого замыкания, если оператор

if (cake != null && cake.frosting != null && cake.frosting.berries != null) ...

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

Возможно ли использовать какой-либо метод расширения или это будет языковая функция, или это просто плохая идея?

Ответы [ 16 ]

1 голос
/ 05 марта 2013

Существует Может быть, проект codeplex , который реализует Возможно или IfNotNull, используя лямбда-выражения для глубоких выражений в C #

Пример использования:

int? CityId= employee.Maybe(e=>e.Person.Address.City);

ссылка была предложена в аналогичном вопросе Как проверить наличие нулей в глубоком лямбда-выражении?

1 голос
/ 17 января 2012

Попробуйте этот код:

    /// <summary>
    /// check deep property
    /// </summary>
    /// <param name="obj">instance</param>
    /// <param name="property">deep property not include instance name example "A.B.C.D.E"</param>
    /// <returns>if null return true else return false</returns>
    public static bool IsNull(this object obj, string property)
    {
        if (string.IsNullOrEmpty(property) || string.IsNullOrEmpty(property.Trim())) throw new Exception("Parameter : property is empty");
        if (obj != null)
        {
            string[] deep = property.Split('.');
            object instance = obj;
            Type objType = instance.GetType();
            PropertyInfo propertyInfo;
            foreach (string p in deep)
            {
                propertyInfo = objType.GetProperty(p);
                if (propertyInfo == null) throw new Exception("No property : " + p);
                instance = propertyInfo.GetValue(instance, null);
                if (instance != null)
                    objType = instance.GetType();
                else
                    return true;
            }
            return false;
        }
        else
            return true;
    }
0 голосов
/ 31 марта 2014

Если вам нужно добиться этого, сделайте это:

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

Color color = someOrder.ComplexGet(x => x.Customer.LastOrder.Product.Color);

или

Color color = Complex.Get(() => someOrder.Customer.LastOrder.Product.Color);

Реализация вспомогательного класса

public static class Complex
{
    public static T1 ComplexGet<T1, T2>(this T2 root, Func<T2, T1> func)
    {
        return Get(() => func(root));
    }

    public static T Get<T>(Func<T> func)
    {
        try
        {
            return func();
        }
        catch (Exception)
        {
            return default(T);
        }
    }
}
0 голосов
/ 09 июня 2013

Мне нравится подход, принятый Objective-C:

«Язык Objective C использует другой подход к этой проблеме и не вызывает методы для nil, а вместо этого возвращает nil для всех таких вызовов».

if (cake.frosting.berries != null) 
{
    var str = cake.frosting.berries...;
}
0 голосов
/ 02 марта 2013

Я немного изменил код с здесь , чтобы он работал на заданный вопрос:

public static class GetValueOrDefaultExtension
{
    public static TResult GetValueOrDefault<TSource, TResult>(this TSource source, Func<TSource, TResult> selector)
    {
        try { return selector(source); }
        catch { return default(TResult); }
    }
}

И да, это, вероятно, не оптимальное решение из-за влияния на попытки / улов производительности, но оно работает:>

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

var val = cake.GetValueOrDefault(x => x.frosting.berries.loader);
0 голосов
/ 11 января 2011

Я отправил это вчера вечером, а потом мой друг указал мне на этот вопрос.Надеюсь, поможет.Затем вы можете сделать что-то вроде этого:

var color = Dis.OrDat<string>(() => cake.frosting.berries.color, "blue");


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;

namespace DeepNullCoalescence
{
  public static class Dis
  {
    public static T OrDat<T>(Expression<Func><T>> expr, T dat)
    {
      try
      {
        var func = expr.Compile();
        var result = func.Invoke();
        return result ?? dat; //now we can coalesce
      }
      catch (NullReferenceException)
      {
        return dat;
      }
    }
  }
}

Прочитать полный блог здесь .

Этот же друг также предложил вам посмотреть это .

...