好的,所以我已多次阅读过这篇文章,但我还没有听到一种清晰,易懂(且令人难忘)的方法来了解它们之间的区别:
if (x | y)
和
if (x || y)
..在C#的背景下.任何人都可以帮助我学习这个基本事实,以及C#如何具体地对待它们(因为它们似乎做同样的事情).如果给定代码片段之间的差异是无关紧要的,我应该将其默认为最佳实践?
||
是逻辑或运算符.看到这里.它评估true
至少一个操作数是否为真.您只能将它与布尔操作数一起使用; 将它与整数操作数一起使用是错误的.
// Example var one = true || bar(); // result is true; bar() is never called var two = true | bar(); // result is true; bar() is always called
|
是或运营商.看到这里.如果应用于布尔类型,则计算true
至少一个操作数是否为真.如果应用于整数类型,则计算为另一个数字.如果至少一个操作数具有相应的位集,则该数字的每个位设置为1.
// Example var a = 0x10; var b = 0x01; var c = a | b; // 0x11 == 17 var d = a || b; // Compile error; can't apply || to integers var e = 0x11 == c; // True
对于布尔操作数,a || b
是相同于a | b
,条件是唯一的例外b
,如果不评估a
为真.因此,||
据说是"短路".
如果给定代码片段之间的差异是无关紧要的,我应该将其默认为最佳实践?
如上所述,差异并非无关紧要,因此这个问题部分没有实际意义.至于"最佳实践",没有一个:您只需使用正确的操作符即可.在一般情况下,人们倾向于||
在|
布尔操作数,因为你可以肯定它不会产生不必要的副作用.
当与布尔操作数一起使用时,运算|
符就像逻辑运算符一样||
,但区别在于||
运算符执行短路评估而|
运算符不执行.
这意味着始终使用|
运算符计算第二个操作数,但使用||
运算符时,仅在第一个操作数计算为false时才计算第二个操作数.
对于两个操作符,表达式的结果总是相同的,但如果第二个操作数的求值导致其他内容发生变化,那么只有在使用|
运算符时才会发生这种情况.
例:
int a = 0; int b = 0; bool x = (a == 0 || ++b != 0); // here b is still 0, as the "++b != 0" operand was not evaluated bool y = (a == 0 | ++b != 0); // here b is 1, as the "++b != 0" operand was evaluated.
||
运算符的短路评估可用于编写较短的代码,因为仅在第一个操作数为真时才评估第二个操作数.而不是像这样写:
if (str == null) { Console.WriteLine("String has to be at least three characters."); } else { if (str.Length < 3) { Console.WriteLine("String has to be at least three characters."); } else{ Console.WriteLine(str); } }
你可以像这样写:
if (str == null || str.Length < 3) { Console.WriteLine("String has to be at least three characters."); } else{ Console.WriteLine(str); }
仅当第一个操作数为false时才计算第二个操作数,因此您知道可以安全地在第二个操作数中使用字符串引用,因为如果计算第二个操作数,它不能为空.
在大多数情况下,您可能希望使用||
运算符而不是|
运算符.如果第一个操作数为false,则无需计算第二个操作数以获得结果.此外,很多人(显然)不知道你可以使用|
带有布尔操作数的运算符,因此当他们在代码中使用这种方式时,他们会感到困惑.
他们不一样.一个是按位OR,一个是逻辑OR.
X || Y,是逻辑的,或者与"X或Y"相同,适用于bool值.它用于条件或测试.在这种情况下,X和Y可以替换为任何计算为bool的表达式.例:
if (File.Exists("List.txt") || x > y ) { ..}
如果两个条件中的任何一个为真,则子句的计算结果为true.如果第一个条件为真(如果文件存在),则第二个条件不需要也不会被评估.
单个管道(|)是按位OR.要知道这意味着什么,您必须了解数字如何存储在计算机中.假设您有一个保持值为15的16位数量(Int16).它实际上存储为0x000F(十六进制),与二进制的0000 0000 0000 1111相同.按位OR取两个量并将每对相应位的OR组合在一起,因此如果该位在任一数量中为1,则结果为1.因此,如果a = 0101 0101 0101 0101(以十六进制计算为0x5555)和b = 1010 1010 1010 1010(即0xAAAA),则a | b = 1111 1111 1111 1111 = 0xFFFF.
您可以在C#中使用按位OR(单个管道)来测试是否打开了一个或多个特定位组.如果你有12个布尔值或二进制值来测试,你可能会这样做,而且它们都是独立的.假设您有一个学生数据库.一组独立的布尔可能是类似的东西,例如男/女,家庭/校园,当前/非当前,已登记/未登记等.而不是为每个值存储一个布尔字段,您可以存储每一个只有一个位.男性/女性可能是第1位.注册/不可能是第2位.
然后你可以使用
if ((bitfield | 0x0001) == 0x0001) { ... }
作为测试,看看是否没有打开位,除了"student is male"位,这被忽略.咦?好吧,按位OR为每个数字中的每个位返回1.如果按位或以上的结果= 0×0001,这意味着有没有位位域开启,除了可能在第一位(0×0001),但你不能肯定地告诉第一位是开的,因为它它蒙面了.
有一个对应的&&和&,它是逻辑AND和按位AND.他们有类似的行为.
您可以使用
if ((bitfield & 0x0001) == 0x0001) { ... }
查看位域中是否打开了第一位.
编辑:我不敢相信我为此投了票!
很好的答案,但让我补充说,||
如果左侧表达式是,则不评估右侧表达式true
.如果评估术语是a)表现密集型或b)产生副作用(罕见),请记住这一点.
与迄今为止的大多数答案不同,其含义与C++中的含义并不完全相同.
对于评估为布尔值的任何两个表达式A和B,A || B和A | B几乎做同样的事情.
A | 乙评估两个 A和B,如果他们中的一个计算结果为真,结果为真.
A || B几乎完全相同,除了它首先评估A,然后只在必要时评估B. 如果A或B为真,则整个表达式为真,如果A为真,则不需要对B进行全部测试.所以|| 短路,并在可能的情况下跳过评估第二个操作数,其中| 运营商将始终评估两者.
| 操作员不经常使用,而且通常不会有所作为.我能想到的唯一一个常见的例子就是:
if ( foo != null || foo.DoStuff()){ // assuming DoStuff() returns a bool }
这是有效的,因为如果左侧测试失败,则永远不会调用DoStuff()成员函数.也就是说,如果foo为null,我们就不会在其上调用DoStuff.(这会给我们一个NullReferenceException).
如果我们使用了| 运算符,无论foo是否为null,都会调用DoStuff().
在整数上,只有| 运算符是定义的,并且是按位OR,正如其他答案所描述的那样.|| 虽然operator不是为整数类型定义的,但是很难让它们在C#中混淆.