寻找一些最佳实践指南。假设我有一行代码如下:
Color color = someOrder.Customer.LastOrder.Product.Color;
在正常情况下,Customer,LastOrder,Product和Color可能为null
。但是,如果路径中的任何一个对象为null,我希望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指定为颜色?或者在使用这种嵌套引用时如何避免NullReferenceExceptions的任何想法?
答案 0 :(得分:10)
您正在寻找空安全解除引用运算符。
Color color = someOrder?.Customer?.LastOrder?.Product?.Color;
不幸的是C#不支持它。也许它会在稍后添加,但目前还没有计划这样做。
相关强>
答案 1 :(得分:1)
最佳做法是遵循Law of Demeter,听起来像:不要与陌生人交谈。即对象应该避免调用另一个方法返回的成员对象的方法。这允许编写更少耦合,更易于维护和可读的代码。
所以,避免使用someOrder.Customer.LastOrder.Product.Color
之类的“火车残骸”,因为它们完全违反了得墨忒耳法则。甚至很难理解这段代码的商业含义。为什么你得到其他订单的产品颜色,这不是现在的订单?
可能的方法来消除火车残骸 - 推动功能更接近有趣的残骸结束。在您的情况下,还要考虑将最后一个产品传递给您的方法,而不是使用某些订单。
答案 2 :(得分: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);
}
}
}
答案 3 :(得分:0)
我肯定更喜欢第一种方法......第二种方法利用程序流程的异常机制,这是不好的做法恕我直言......
AFAIK在C#中没有快捷方式或“空值安全解除引用运算符”。
答案 4 :(得分:0)
定义访问嵌套属性的唯一方法。 例如像这样
private Customoer GetCustomer(Order order)
{
return order != null ? order.Customer : null;
}
private Order GetLastOrder(Customer customer)
{
return customer != null ? customer.LastOrder : null;
}
使用已定义的方法访问应用程序中的属性
答案 5 :(得分:0)
您还可以在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");
}
}
}