关于编码风格:为什么人们经常在C#中看到“ null!= variable”而不是“ variable!= null”?

Why does one often see “null != variable” instead of “variable != null” in C#?

在c#中,陈述条件的顺序的执行速度是否有差异?

1
2
if (null != variable) ...
if (variable != null) ...

从最近开始,我经常看到第一个,自从我习惯了第二个以来,它引起了我的注意。

如果没有区别,第一个的优势是什么?


这是C语言的保留。在C语言中,如果您使用错误的编译器或没有将警告提高到足够高的水平,则将在没有警告的情况下进行编译(实际上是合法代码):

1
2
// Probably wrong
if (x = 5)

当你实际上可能意味着

1
if (x == 5)

您可以通过以下方法在C中解决此问题:

1
if (5 == x)

此处输入错误将导致代码无效。

现在,在C#中,这真是个难题。除非要比较两个布尔值(IME很少见),否则您可以编写更具可读性的代码,因为" if"语句要求以布尔值开头,并且" x=5"的类型为Int32 ,而不是Boolean

我建议,如果您在同事的代码中看到了这一点,请以现代语言的方式对其进行教育,并建议他们将来编写更自然的形式。


有充分的理由先使用null:if(null == myDuck)

如果您的class Duck覆盖了==运算符,则if(myDuck == null)可以进入无限循环。

首先使用null会使用默认的相等比较器,并且实际上会执行您想要的操作。

(我听说您最终会习惯于阅读用这种方式编写的代码-我只是还没有经历过这种转换)。

这是一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class myDuck
{
    public int quacks;
    static override bool operator ==(myDuck a, myDuck b)
    {
        // these will overflow the stack - because the a==null reenters this function from the top again
        if (a == null && b == null)
            return true;
        if (a == null || b == null)
            return false;

        // these wont loop
        if (null == a && null == b)
            return true;
        if (null == a || null == b)
            return false;
        return a.quacks == b.quacks; // this goes to the integer comparison
    }
}


就像大家已经指出的那样,它或多或少地来自C语言,如果您不小心忘记了第二个等号,则可能会得到错误的代码。但是还有另一个与C#相匹配的原因:可读性。

仅举一个简单的例子:

1
2
3
4
5
6
7
8
if(someVariableThatShouldBeChecked != null
   && anotherOne != null
   && justAnotherCheckThatIsNeededForTestingNullity != null
   && allTheseChecksAreReallyBoring != null
   && thereSeemsToBeADesignFlawIfSoManyChecksAreNeeded != null)
{
    // ToDo: Everything is checked, do something...
}

如果您只是将所有空词交换到开头,则可以更轻松地发现所有检查:

1
2
3
4
5
6
7
8
if(null != someVariableThatShouldBeChecked
   && null != anotherOne
   && null != justAnotherCheckThatIsNeededForTestingNullity
   && null != allTheseChecksAreReallyBoring
   && null != thereSeemsToBeADesignFlawIfSoManyChecksAreNeeded)
{
    // ToDo: Everything is checked, do something...
}

因此,此示例可能是一个不好的示例(请参阅编码指南),但请考虑一下您快速滚动浏览完整的代码文件。通过简单地看到模式

1
if(null ...

您立即知道接下来会发生什么。

如果相反,您总是必须扫描到该行的末尾以查看无效检查,只是让您绊倒一秒钟以找出进行哪种检查。因此,语法突出显示也许可以为您提供帮助,但是当这些关键字位于行尾而不是行尾时,您总是会变慢。


我猜这是一个切换语言的C程序员。

在C中,您可以编写以下内容:

1
2
3
4
5
int i = 0;
if (i = 1)
{
    ...
}

注意那里使用了一个等号,这意味着代码将给变量i分配1,然后返回1(一个赋值是一个表达式),并在if语句中使用1,这将被视为true。换句话说,以上是一个错误。

但是,在C#中,这是不可能的。两者之间确实没有区别。


遵循此约定我看不出任何优势。在不存在布尔类型的C语言中,编写

1
if( 5 == variable)

而不是

1
if (variable == 5)

因为如果忘记其中一个等号,您最终会得到

1
if (variable = 5)

将5赋给变量,并始终求值为true。但是在Java中,布尔值是布尔值。并且使用!=根本没有任何理由。

不过,一个好的建议是写

1
if (CONSTANT.equals(myString))

而不是

1
if (myString.equals(CONSTANT))

因为它有助于避免NullPointerExceptions。

我的建议是要求对规则进行辩护。如果没有,为什么要遵循?它不利于可读性


在早期,人们会忘记"!" (或额外的'='代表相等性,这很难发现),然后分配而不是进行比较。将null放在前面可以消除该错误的可能性,因为null不是l值(即,它不能分配给它)。

在当今有条件的情况下执行赋值操作时,大多数现代编译器都会发出警告,而C#实际上会给出错误。大多数人只是坚持使用var == null方案,因为它对某些人来说更容易阅读。


许多人指出,它主要是用旧的C代码来识别编译错误,因为编译器认为它是合法的

像Java这样的新编程语言go足够聪明,可以捕获此类编译错误

人们不应该像代码中的条件那样使用" null!= variable",因为它非常不可读


对我来说,一直是您喜欢哪种风格

@Shy-再一次,如果您使运算符感到困惑,那么您应该想得到一个编译错误,否则您将在运行代码时遇到一个错误-一个错误又回来了,并在以后咬住了您,因为它产生了意外的行为


还有一件事...如果将变量与常量(例如整数或字符串)进行比较,则将常量放在左侧是一种好习惯,因为您永远不会遇到NullPointerExceptions:

1
2
3
4
int i;
if(i==1){        // Exception raised: i is not initialized. (C/C++)
  doThis();
}

1
2
3
4
int i;
if(1==i){        // OK, but the condition is not met.
  doThis();
}

现在,由于默认情况下C#实例化了所有变量,因此您不应该使用该语言来解决该问题。