更新:从Visual Studio 2015开始,C#编译器(语言版本6)现在可以识别?.
运算符,从而使“深度null检查”变得轻而易举。有关详细信息,请参见此答案。
除了重新设计代码(如
建议的已删除答案)外,另一个(虽然很糟糕)的选择是使用一个try…catch
块来查看NullReferenceException
在深层属性查找期间是否发生了错误。
try
{
var x = cake.frosting.berries.loader;
...
}
catch (NullReferenceException ex)
{
// either one of cake, frosting, or berries was null
...
}
由于以下原因,我个人不会这样做:
- 看起来不太好。
- 它使用异常处理,该异常处理应针对特殊情况,而不是您在正常操作过程中经常发生的异常。
NullReferenceException
可能永远都不应明确捕获。(请参阅此问题。)
因此,可以使用某些扩展方法还是它是一种语言功能,[...]
几乎可以肯定这必须是语言功能(在C#6中以.?
and ?[]
运算符的形式提供),除非C#已经具有更复杂的惰性求值,或者除非您要使用反射(这可能也不是反射功能)。基于性能和类型安全性的好主意)。
由于没有方法可以简单地传递cake.frosting.berries.loader
给函数(该函数将被评估并引发null引用异常),因此您将必须通过以下方式实现常规查找方法:它接受一个对象和属性名称以抬头:
static object LookupProperty( object startingPoint, params string[] lookupChain )
{
// 1. if 'startingPoint' is null, return null, or throw an exception.
// 2. recursively look up one property/field after the other from 'lookupChain',
// using reflection.
// 3. if one lookup is not possible, return null, or throw an exception.
// 3. return the last property/field's value.
}
...
var x = LookupProperty( cake, "frosting", "berries", "loader" );
(注意:代码已编辑。)
您很快就会发现使用这种方法的几个问题。首先,您不会获得任何类型安全性,也不会获得简单类型的属性值的装箱。其次,null
如果出现问题,则可以返回,并且必须在调用函数中进行检查,或者引发异常,然后返回到开始的地方。第三,它可能很慢。第四,它看起来比开始时要难看。
[...]还是一个坏主意?
我要么留在:
if (cake != null && cake.frosting != null && ...) ...
或采用Mehrdad Afshari的上述答案。
PS:回到我写这个答案时,我显然没有考虑将表达式树用于lambda函数。参见例如@driis的答案,以寻求该方向的解决方案。它也是基于一种反射,因此可能不如简单的解决方案(if (… != null & … != null) …
)表现出色,但从语法角度来看可能会更好。