1

我有一个关于编程风格和 C# 语言设计的问题,我很想知道是否有更好的方法来做我正在做的事情。

如果您有一个复杂的数据对象,其属性可以为空,但您想检查或操作数据(如果存在),则不能编写这样的行

if(Myobject.MyNestedObject != null || Myobject.MyNestedObject.Property != null)
{
   //code
}

因为编译器实际上会调用两行代码来评估 if 语句。

相反,您必须(我相信)写:

if(Myobject.MyNestedObject != null)
{
   if(Myobject.MyNestedObject.Property != null)
   {
      //code
   }
}

还有比这更好的风格吗?我正在尝试考虑如何使用 null coalesce (??) 但如果您尝试在同一语句中使用 MyNestedObject 的任何内容,它仍然会抛出。

更多信息:

    L_01b4: ldarg.1 
    L_01b5: callvirt instance class [Myassembly]MyClass.MyObject [MyAssembly]MyClass::get_MyObject()
    L_01ba: brtrue.s L_01cc
    L_01bc: ldarg.1 
    L_01bd: callvirt instance class [MyAssembly]MyClass.MyObject [MyAssembly]MyClass::get_MyObject()
    L_01c2: callvirt instance class [MyAssembly]MyClass.MyNestedObject [MyAssembly]MyClass.MyNestedObject::get_MyNestedObject()
    L_01c7: ldnull 
    L_01c8: ceq 
    L_01ca: br.s L_01cd
    L_01cc: ldc.i4.0 
    L_01cd: stloc.2 
    L_01ce: ldloc.2 
    L_01cf: brtrue L_0285
    L_01d4: nop 

据我了解,在 L_01ba 处,如果调用返回 true、不为 null 或非 0(即,如果对象为 null,则不采用分支,然后控制流线性继续)。这当然会执行 L_01c2 ,它会抛出一个空引用异常,因为 Myclass.MyObject 是空的。

我是不是错过了什么。这是 .net 3.5 C# 编译器。

4

4 回答 4

19

结合@Chris 和@aJ 答案:

我认为您需要 && 运算符,而不是 ||。

if (Myobject.MyNestedObject != null &&
    Myobject.MyNestedObject.Property != null)
{
    //code
}

并且 C# 的 && 运算符使用短路求值,因此如果第一个表达式返回 false,则不会对第二个表达式求值。

...

于 2009-04-20T04:37:27.633 回答
4
if( Myobject.MyNestedObject != null && 
             Myobject.MyNestedObject.Property != null)
{
//code
}
于 2009-04-20T04:31:36.447 回答
2

C# 使用惰性检查,所以你的第一个代码应该没问题(当然 || 更改为 &&!)

更新 - 这里是:http: //msdn.microsoft.com/en-gb/library/6373h346.aspx “操作

x || 是的

对应操作

x | 是的

除了如果 x 为真,则不计算 y(因为无论 y 的值是什么,OR 运算的结果都是真)。这称为“短路”评估。"

再次更新 - 应该使用 &&!

于 2009-04-20T04:29:58.180 回答
1

我将添加强制性建议,即必须挖掘公共属性层通常意味着您暴露了太多内部状态,并且您正在遍历的类应该为您完成这项工作。我还希望一个对象首先确保其属性不返回 null。

当然有边缘情况,但这些都是很好的经验法则。

于 2009-04-20T08:32:18.067 回答