为什么使用 null == myVar 而不是 myVar == null?

6
6个回答

20

为避免意外的输错,myVar = null 这种做法是一个老习惯了。在某些语言中仍然有用,但是C#会保护你不犯这个错误,所以在C#中这样做并不必要。


此外,通常习惯说“someConst == myVar”,其中在这种情况下someConst恰好为null。一些脚本语言可能会将上述内容翻译为“someConst.equals(myVar)”,如果你反过来做,可能会得到一个NPE。 - Bugmaster
更正:C# 不会让你这样做。 - Noldorin
@Noldorin,你如何在VB.NET中进行条件赋值? - Rex M
@Rex - 我认为Noldorin只是在区分语言和库(这是一个很好的区分)。此外,只要赋值是布尔值到布尔变量,C#确实允许在条件语句中进行赋值(但这会生成警告)。 - Andrew Hare
@Andrew 这个说法很合理。通常我们会把.NET简称为C#和VB.NET,但是我想这可能会引起一些混淆,所以我会做出改变。 - Rex M
null == myVar 这种写法比 myVar == null 更不易读。 - Konstantin Spirin

8

这是从C语言中遗留下来的,旧的编译器无法捕获到这个问题:

if (foo = null)

当你说这个时候:

if (foo == null)

经典笑话例子是这个错误:
if (fireTheNukes = true)
    fireTheNukes();

这被普遍认为是一种陈旧的模式,因为任何值得其盐的编译器都会捕捉到条件语句中的赋值。我建议您在代码中避免使用此模式,因为它在现今已没有任何用处。


@Andrew:我认为 if(foo = null) 是一个完全有效的语句(将值分配给 foo,然后检查它是否为真)。我认为这与编译器没有“捕获”它无关。 - Esteban Araya
@Esteban - 用什么语言和编译器?虽然C#编译器允许在条件语句中进行布尔赋值,但它还会生成一个“你真的想这样做吗?”的警告。 - Andrew Hare

2

这是一种老式的防御习惯。如果你把常量放在左边,那么忘记第二个等号会导致编译错误。在更常见的格式中,忘记第二个等号会导致将 null 赋值给你的变量。

换句话说,

myVar = null

是有害和令人惊讶的,然而

null = myVar

被编译器捕捉。


2

这来自于C/C++,用于捕捉漏掉一个等号的情况:

myVar = null

但在C#中并不需要它。


2

这是C程序员的一种习惯,在此情况下已经被带到了C#中,但实际上是完全不必要的。

在C中,如果你误输入了if (myVar = null),编译器将执行赋值操作而不会抱怨。交换myVarnull的顺序可以确保在意外将==误写为=时生成编译器错误。然而,C#无论哪种情况都会生成编译器警告,因此这个怪癖是不必要的。


1
正如其他人所提到的,这是一种防御性策略,旨在防止由于在C和一些C衍生语言(包括C#)中赋值表达式会计算出该赋值的值而可能引起的问题。这就是允许你执行以下操作的原因:
if (a = true) { /* This will always get done, as "a = true" evals to true */ }

并且

int a = b = c = d = 10;

由于赋值运算符是右结合的,因此这实际上是

int a = (b = (c = (d = 10)));

每个花括号内的表达式都将求值为赋值的值,这里是10,因此a、b、c和d都将是10。

为避免潜在的错误——混淆赋值和等式运算符——一些程序员更喜欢始终将常量放在左边,就好像意外使用了赋值运算符,编译器会抱怨无法对常量进行赋值。

然而,在C#中,这不是特别大的问题,原因有两个。首先,与C不同,C#不允许将任意值解释为布尔值。

这在C中是必要的,因为它没有真正的布尔类型,只依靠其他值的解释,例如整数(其中0为假,非零为真)或指针(其中NULL为假)。这意味着你可以做一些像这样的事情:

if (10) { /* This will always get done */ }
if (0) { /* This will never get done */ }
if (p) { /* This will get done is p is not null */ }
if (NULL) { /* This will never get done */ }

然而,由于C#不允许将任意表达式解释为布尔值,因此这些在C#中将无法工作。这也意味着

if (a = 10) { }

在C#中无法编译,因为表达式“a = 10”的值为10,不能被解释为所需的布尔值。

第二个原因是它不再是一个问题,因为在现在更小的情况下,赋值的结果可以被解释为布尔值,编译器会发出警告以确保您真的想这样做。

可以使用以下方法抑制警告

#pragma warning disable 665

然而,这种代码的存在通常是糟糕的代码气味,最好通过重构使代码更清晰。


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