C# if 语句中嵌套 null 检查
我对编程风格和 C# 语言设计有疑问,我很想知道是否有更好的方法来完成我正在做的事情。
如果您有一个复杂的数据对象,其属性可以为 null,但您想要检查或操作数据(如果存在),则不能编写这样的行,
if(Myobject.MyNestedObject != null || Myobject.MyNestedObject.Property != null)
{
//code
}
因为编译器实际上会调用这两行代码来评估 if 语句。
相反,你必须(我相信)写:
if(Myobject.MyNestedObject != null)
{
if(Myobject.MyNestedObject.Property != null)
{
//code
}
}
还有比这更好的风格吗? 我正在尝试考虑如何使用空合并(??),但如果您尝试在同一语句中使用 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# 编译器。
I have a question on programming style and C# language design in general, I'd love to know if there is a better way to do what I'm doing.
If you have a complex data object, with properties that can be null but you want to check or operate on data if it is there, you cannot write a line like so
if(Myobject.MyNestedObject != null || Myobject.MyNestedObject.Property != null)
{
//code
}
Because the compiler will actually call both lines of code to evaluate the if statement.
Instead you must (I believe) write :
if(Myobject.MyNestedObject != null)
{
if(Myobject.MyNestedObject.Property != null)
{
//code
}
}
Is there a better style than this? I'm trying to think of how to use null coalesce (??) but it would still throw if you try to use anything of MyNestedObject in the same statement.
More info:
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
From my understanding it's saying that at L_01ba if the call returns true, not null or non-0 (i.e if the object is null, the branch isn't taken and then control flow continues linearly). This then will of course execute L_01c2 which will throw a null reference exception, as Myclass.MyObject is null.
Have I missed something. This is the .net 3.5 C# compiler.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
结合 @Chris 和 @aJ 答案:
我认为你想要 && 运算符,而不是||。
还有 C# 的 && 运算符使用短路计算,因此如果第一个表达式返回 false,则不会计算第二个表达式。
...
Combining @Chris and @aJ answer:
I think you want the && operator, not ||.
And C#'s && operator use short-circuit evaluation, so if the first expression returns false, the second expression will not be evaluated.
...
C# 使用惰性检查,因此您的第一个代码应该没问题(当然将 || 更改为 &&!)
更新 - 这里是:
http://msdn.microsoft.com/en-gb/library/6373h346。 ASPX
”
运算
x || y
对应于操作
x | y
,但如果 x 为 true,则不计算 y(因为无论 y 的值是什么,OR 运算的结果都是 true)。 这称为“短路”评估。
"
再次更新 - 应该使用 &&!
C# uses lazy checking, so your first code should be fine (with || changed to && of course!)
Update - Here it is:
http://msdn.microsoft.com/en-gb/library/6373h346.aspx
"
The operation
x || y
corresponds to the operation
x | y
except that if x is true, y is not evaluated (because the result of the OR operation is true no matter what the value of y might be). This is known as "short-circuit" evaluation.
"
Update again - should be using &&!
我将添加强制性建议,即必须挖掘公共属性层通常意味着您暴露了太多的内部状态,并且您正在遍历的类应该为您完成这项工作。 我还希望一个对象能够确保其属性首先不会返回 null。
当然也有一些边缘情况,但这些都是很好的经验法则。
I'm going to add the obligatory advice that having to dig through layers of public properties usually means you are exposing too much internal state, and that the classes you are traversing should be doing this work for you. I would also expect an object to ensure its properties do not return null in the first place.
There are edge cases of course, but these are good rules of thumb.