如何检查嵌套引用中的空值

10

希望得到一些最佳实践指导。假设我有一行像这样的代码:

Color color = someOrder.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) {}

第一种方法显然可行,但编写起来可能有些繁琐,阅读起来也更加困难。第二种方法稍微容易一些,但使用异常处理来处理这个问题可能不是一个好主意。还有其他检查null并在必要时将null分配给颜色的捷径吗?或者对于使用嵌套引用时如何避免NullReferenceExceptions有什么想法吗?

2
可能是重复的问题:深度空值检查,有更好的方法吗? - Mark Byers
@MarkByers 是的,谢谢你提供另一个问题的参考。 - Eren Ersönmez
6个回答

14
您正在寻找空值安全解引用运算符。
Color color = someOrder?.Customer?.LastOrder?.Product?.Color;

很遗憾,C#不支持此功能。也许将来会增加,但目前没有计划。

相关问题


正如上面的“相关”链接中所指出的那样,Null-conditional运算符?.和?[]是在C# 6(大约2015年7月)中添加的。 - Rich K

2
最佳实践是遵循Demeter法则,其原则是不要与陌生人交谈。即对象应避免调用另一个方法返回的成员对象的方法。这样可以编写耦合度更低、更易维护和可读性更高的代码。
因此,避免使用像someOrder.Customer.LastOrder.Product.Color这样的“火车失事”,因为它们完全违反了Demeter法则。甚至很难理解这段代码具有什么业务含义。为什么要获取某个其他订单的产品颜色,而不是当前订单的颜色呢?
消除“火车失事”的可能方法是将功能推向失事的有趣端点。在你的情况下,还应考虑将最后一个产品传递给你的方法,而不是使用某个订单。

谢谢。我会看一下LoD。顺便说一句,那段代码只是我编的一个例子 - 没有业务意义。 - Eren Ersönmez
1
我喜欢有人这么说,即使它并没有直接回答问题。毫无疑问,你必须编写复杂的代码,以确保不会在这样的代码中尝试使用空引用。虽然了解技术上的答案很重要,包括C#能够做什么和不能做什么,但这种代码应该让你害怕并检查你的整体设计。 - Chris Gomez

1

在你需要实现这个功能的地方,执行以下操作。

用法

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

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

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

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

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


0

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

据我所知,在C#中没有快捷方式或“null安全解引用运算符”。


0

在if语句中,您还可以使用Null-conditional运算符。如果存在大量嵌套值,则非常有用。

例如:

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接