【问题标题】:How to check for null in nested references如何检查嵌套引用中的空值
【发布时间】:2012-05-08 20:45:35
【问题描述】:

寻找一些最佳实践指导。假设我有这样一行代码:

Color color = someOrder.Customer.LastOrder.Product.Color;

其中 Customer、LastOrder、Product 和 Color 在正常情况下可能是 null。但是,如果路径中的任何一个对象为空,我希望颜色为空;为了避免空引用异常,我需要检查每个对象的空条件,例如

Color color = someOrder == null ||
              someOrder.Customer == null || 
              someOrder.Customer.LastOrder == null ||
              someOrder.Customer.Product == null ? 
              null : someOrder.Customer.LastOrder.Product.Color;

或者我可以这样做

Color color = null;
try {color = someOrder.Customer.LastOrder.Product.Color}
catch (NullReferenceException) {}

第一种方法显然有效,但代码似乎有点乏味且难以阅读。第二种方法更简单一些,但为此使用异常处理可能不是一个好主意。

是否有另一种快捷方式来检查空值并在必要时将空值分配给颜色?或者对使用此类嵌套引用时如何避免 NullReferenceExceptions 有任何想法?

【问题讨论】:

标签: c# c#-4.0 nullreferenceexception


【解决方案1】:

您正在寻找 null 安全的解引用运算符。

Color color = someOrder?.Customer?.LastOrder?.Product?.Color;

不幸的是,C# 不支持它。也许稍后会添加它,但目前没有计划这样做。

相关

【讨论】:

  • 如上面“相关”链接中所述,Null 条件运算符 ?。和 ?[] 是在 C# 6 中添加的(大约 2015 年 7 月)
【解决方案2】:

我肯定更喜欢第一种方法...第二种方法利用程序流的异常机制,恕我直言,这是不好的做法...

AFAIK 在 C# 中没有快捷方式或“空安全解引用运算符”。

【讨论】:

    【解决方案3】:

    定义访问嵌套属性的唯一方法。 比如这样的

    private Customoer GetCustomer(Order order)
    {
      return order != null ? order.Customer : null;
    }
    
    private Order GetLastOrder(Customer customer)
    {
       return customer != null ? customer.LastOrder : null;
    }
    

    使用定义的方法在应用程序中访问您的属性

    【讨论】:

      【解决方案4】:

      最佳做法是遵循Law of Demeter,这听起来像是:不要与陌生人交谈。 IE。 object 应避免调用由另一个方法返回的成员对象的方法。这允许编写更少耦合、更易维护和可读的代码。

      所以,避免使用像someOrder.Customer.LastOrder.Product.Color 这样的“火车残骸”,因为它们完全违反了得墨忒耳法则。甚至很难理解这段代码有什么商业意义。为什么你会得到其他订单产品的颜色,而不是当前订单?

      移除火车残骸的可能方法 - 将功能推到更接近有趣的残骸末端。在您的情况下,还可以考虑将最后一个产品传递给您的方法,而不是使用某些顺序。

      【讨论】:

      • 谢谢。我来看看LoD。顺便说一句,代码只是我编的一个例子——没有商业意义。
      • 我喜欢有人这样说,即使它没有直接回答问题。毫无疑问,您必须编写复杂的代码以确保您最终不会尝试在这样的代码中使用空引用。虽然了解技术答案很重要,包括 C# 能够做什么和不能做什么,但这种代码应该会吓到您去查看您的整体设计。
      【解决方案5】:

      你需要在哪里做到这一点。

      用法

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

      【讨论】:

        【解决方案6】:

        您还可以在 if 语句中使用 Null 条件运算符。如果有很多嵌套值,它真的很有用。

        例子:

        public class DummyDto
        {
            public string Name { get; set; }
        
            public DummyDto Parent { get; set; }
        }
        
        class Program
        {
            static void Main(string[] args)
            {
        
                var dummyDto = new DummyDto();
        
                //Both if statements will be true below
                if(dummyDto.Parent?.Name == null)
                {
                    Console.WriteLine("DummyDto is null");
                }
        
                if (dummyDto.Parent == null || dummyDto.Parent.Name == null)
                {
                    Console.WriteLine("DummyDto is null");
                }
            }
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-03-18
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-02-14
          • 1970-01-01
          相关资源
          最近更新 更多