C#: 与null比较

18

这两者是否等价:

if (null==myobject)
{
//do something 
}

if (myobject==null)
{
//do something 
}

或者它们会生成不同的代码吗?


14
第一个也被称为Yoda条件。 - Sebastian Ðymel
6个回答

41

在99%的情况下,这段代码是等效的。

唯一的例外是当涉及对象的类型重写了==运算符时。这种情况下可能会引入一个bug,在其中一个参数为null时会出现问题。

我之前见过一个特定的例子:

public static bool operator==(Student left, Student right) {
  return left.Equals(right);
}

如果 null 位于左侧,这将会失败,但如果 null 位于右侧,则可能不会失败。

虽然这是一个相当边缘的情况。


解决方案是:if((object)left == null)if(ReferenceEquals(left, null))。前者可能更高效。 - yfeldblum
@Justice,我从未调查过JIT,但如果你使用Object.Reference equals,C#将生成一个方法调用。在没有operator==的情况下,C#将使用IL操作码ceq进行直接值比较。我猜测ceq更快。 - JaredPar
4
@Justice,但永远不要对性能做任何假设,相信分析器 :) - JaredPar
1
需要明确的是:这并不意味着一个比另一个更正确。错误可以通过两种方式引入。操作符可以重写为 return right.Equals(left);,然后如果 right 学生为 null (myobject == null),代码将崩溃。 - Steven Liekens
1
无论操作数的顺序如何,null == studentstudent == null都将调用重载的==运算符。因此,我认为这个答案是错误的。 - Dmytro Shevchenko
1
是的,@DmytroShevchenko 是正确的。这是胡说八道的回答。 - Boppity Bop

9
"if"语句中将常量放在左边的形式是从C/C++遗留下来的,因为在这些语言中,你可以在if语句中使用任意表达式。
C#中if语句的语法要求表达式必须评估为bool类型,这意味着if (foo = 0)会编译失败。

哦,太好了。我记得几年前学习C#时,当我在if语句中使用赋值(不小心)时,我曾经收到编译器警告或错误,还有其他安全设备(例如在switch语句中缺少break)。+1 - Devin Jeanpierre
我们曾经故意这样做,同时进行赋值和检查值。C++中的赋值运算符会返回所赋的值。我有点想念那个特性,但很容易被滥用。 - Jasmine
1
@Jasmine:我有时也会使用这种结构——你只需要写成“if ((foo = bar()) == nullptr)”。但通常情况下,这种写法无法通过代码审查——它会被改为“foo = bar(); if (foo == nullptr)”,在我看来更加简洁清晰。 - Larry Osterman
是的,我同意。如果你总是要做这个任务,最好将它放在单独的一行上。这样编译起来可能更顺利。 - Jasmine
1
当您在比较中涉及布尔值时,仍然存在意外赋值的风险,这种情况相当罕见但确实存在:if (wasEnabled == isEnabled()) ... - Roman Starkov

8

The

if (null==myobject) {

这是一种安全的编写if语句的方法。它源于C/C++,其中条件是一个被评估为int的表达式。如果结果为零,则表示false,否则为true。你可以编写类似以下语句:

if (variable == 1) {

但是如果你不小心,你也可能会写成


if (variable = 1) { 

在这种情况下,您有一个总是评估为1且因此始终为真的赋值。

您可以编译并运行它,但结果可能不是您预期的。因此,C / C ++程序员开始编写类似以下内容的代码:

if (1 == variable) {

如果你拼错了这个单词,代码就无法编译通过,所以你必须按照正确的拼写书写。这样做会成为一个好习惯,并且你会在使用其他编程语言时也采用这种方式,比如C#。

1
你所说的misspell是指打错字。说misspell会产生误导。 但你是唯一一个提出这个非常好的观点的人。 - Paul Childs

3

如果您错过了它,或者希望减少混乱,也可以为您的C#类启用C语言风格的空值检查:

class MyObj
{
    public void implicit_null_comparison_demo()
    {
        MyObj mo = null;
        // ...

        if (mo)         //  <-- like so (can also use !mo)
        {
            // it's not null...
        }
        else
        {
            // it's null...
        }
    }

    public static implicit operator bool(MyObj mo)
    {
        return (Object)mo != null;
    }
};

很好。这样做有哪些危险? - Peter Wood
主要是你会错过整个错误类别,其中赋值 = 错误地被用于相等测试 ==,这在 C# 中通常会标记为语法错误,而不像 C 和 **C++**。 - Glenn Slayden
1
没错。这可能是一个难以发现的错误,因为差异仅在于一个字符,并且由于视觉相似性,所以这曾经(仍然?)是关于 C 的常见抱怨。 - Glenn Slayden
我猜一些代码检查工具可以捕捉到它,但这不再是语法错误。 - Peter Wood
@PeterWood 或许吧,但我认为 C# 开发者并没有形成非常强大的“lint”传统,这既是因为(1.)最初的基本语言设计哲学已经从过去的不良经验中吸取教训,避免了我们正在讨论的问题类型,也是因为(2.)IDE 实时编辑体验非常丰富。 - Glenn Slayden

2

0

除非你重载了 ==,否则两种情况都会产生相同的结果。


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