在C#中,条件语句的书写顺序是否会影响执行速度?
if (null != variable) ...
if (variable != null) ...
最近我经常看到第一种,因为我习惯了第二种,所以引起了我的注意。
如果没有区别,第一种有什么优势呢?
在C#中,条件语句的书写顺序是否会影响执行速度?
if (null != variable) ...
if (variable != null) ...
最近我经常看到第一种,因为我习惯了第二种,所以引起了我的注意。
如果没有区别,第一种有什么优势呢?
这是C语言的一种延续。在C语言中,如果你使用了一个糟糕的编译器或者没有将警告设置足够高,那么这段代码将完全没有任何警告就可以编译通过(并且确实是合法的代码):
// Probably wrong
if (x = 5)
你实际上可能想表达的是
if (x == 5)
在C语言中,您可以通过以下方式解决此问题:
if (5 == x)
一个错别字会导致无效的代码。
现在,在C#中这都是小意思。除非你要比较两个布尔值(这很少见),否则你可以编写更易读的代码,因为“if”语句需要以布尔表达式开头,而“x=5
”的类型是Int32
而不是Boolean
。
我建议,如果你在同事的代码中看到这样的写法,你应该教育他们了解现代语言的方式,并建议他们今后写更自然的形式。
else { }
子句,以防有人需要稍后添加内容但忘记写入 else
关键字。 (玩笑话) - Jeppe Stig Nielsen就像大家已经注意到的那样,它更多或少来自于C语言,在那里,如果您不小心忘记第二个等号,可能会得到错误的代码。但是还有另一个原因与C#相匹配:可读性。
只需拿这个简单的例子:
if(someVariableThatShouldBeChecked != null
&& anotherOne != null
&& justAnotherCheckThatIsNeededForTestingNullity != null
&& allTheseChecksAreReallyBoring != null
&& thereSeemsToBeADesignFlawIfSoManyChecksAreNeeded != null)
{
// ToDo: Everything is checked, do something...
}
如果你把所有的null单词移到开头,你就可以更容易地找到所有检查。if(null != someVariableThatShouldBeChecked
&& null != anotherOne
&& null != justAnotherCheckThatIsNeededForTestingNullity
&& null != allTheseChecksAreReallyBoring
&& null != thereSeemsToBeADesignFlawIfSoManyChecksAreNeeded)
{
// ToDo: Everything is checked, do something...
}
所以这个例子可能是一个不好的例子(参考编码准则),但只需想想你快速滚动整个代码文件时所看到的模式。
if(null ...
你立即知道接下来会发生什么。
如果情况反过来,你总是不得不扫描到行末才能看到空值检查,让你需要几秒钟去找出那里进行了什么样的检查。因此,也许语法高亮可以帮助你,但当这些关键字在行末而非行首时,你总是会更慢。
使用null的好处在于: if(null == myDuck)
如果你的Duck类
重写了==
运算符,则if(myDuck == null)
可能会进入无限循环。
使用null
首先使用默认的相等比较器,并实际执行了你想要的操作。
(我听说你最终会习惯阅读写成这种方式的代码 - 只是我还没有经历那种变化)。
以下是一个例子:
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
}
}
==
运算符并停留在那里,您就会看到在两种情况下都使用了用户定义的重载。当然,如果您先检查 a
再检查 b
,然后将 a
的位置从右操作数交换到左操作数可能会有微妙的差异。但是您也可以在检查 b
之前检查 a
,然后 b == null
就成了反转顺序的变量。这样让运算符自己调用会很混乱。相反,将任一操作数(或两个操作数)强制转换为 object
,以获取所需的重载效果。例如 if ((object)a == null)
或 if (a == (object)null)
。 - Jeppe Stig Nielsen我猜这是一位转换语言的C程序员。
在C中,你可以写出以下代码:
int i = 0;
if (i = 1)
{
...
}
在早期,人们会忘记 '!'(或者更难发现的相等性额外 '='),而执行赋值操作而不是比较操作。将 null 放在前面可以消除这种错误的可能性,因为 null 不是一个 l-value(即它不能被赋值)。
现代大多数编译器在条件语句中执行赋值操作时会发出警告,而 C# 实际上会给出错误提示。由于一些人认为 var == null 方案更易读,所以大多数人都坚持使用这种方案。
我不认为遵循这个惯例有任何优势。在 C 语言中,布尔类型不存在,因此写成以下形式是有用的:
if( 5 == variable)
if (variable == 5)
因为如果你忘记了其中一个等号,你最终会得到
if (variable = 5)
在Python中,一个变量可以赋值为5,并且总是计算为true。但在Java中,布尔类型是布尔类型。使用!=时,没有任何理由。
然而,一个好的建议是编写:
if (CONSTANT.equals(myString))
而不是
if (myString.equals(CONSTANT))
对我来说,这总是取决于你喜欢哪种风格。
@Shy - 另一方面,如果您混淆了运算符,则应该希望出现编译错误,否则您将运行具有错误的代码 - 这种错误会在以后产生意外行为时回来咬你一口。
还有一件事...如果你要比较一个变量和一个常量(例如整数或字符串),把常量放在左边是一个好习惯,因为你永远不会遇到NullPointerException:
int i;
if(i==1){ // Exception raised: i is not initialized. (C/C++)
doThis();
}
而
int i;
if(1==i){ // OK, but the condition is not met.
doThis();
}
现在,由于默认情况下C#实例化所有变量,因此您在该语言中不应该遇到该问题。
i
是一个没有正确初始化的随机值,该表达式在C/C++中具有完全相同的语义。 - Raffaello