好的,所以我已多次阅读过这篇文章,但我还没有听到一种清晰,易懂(并且令人难忘)的方法来了解它们之间的区别:
if (x | y)
和
if (x || y)
..在C#的上下文中。任何人都可以帮助我学习这个基本事实,以及C#如何具体地对待它们(因为它们似乎做同样的事情)。如果给定代码片段之间的差异是无关紧要的,我应该将其默认为最佳实践?
答案 0 :(得分:82)
||
是 logical-or 运算符。请参阅 here 。如果至少有一个操作数为真,则计算结果为true
。您只能将它与布尔操作数一起使用;将它与整数操作数一起使用是错误的。
// Example
var one = true || bar(); // result is true; bar() is never called
var two = true | bar(); // result is true; bar() is always called
|
是或运算符。请参阅 here 。如果应用于布尔类型,则如果至少有一个操作数为true,则计算结果为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
与<{1}} 相同,但a | b
为真时不会评估b
的唯一例外情况。因此,a
被称为“短路”。
如果给定代码片段之间的差异是无关紧要的,我应将其默认为最佳实践?
如上所述,差异并非无关紧要,因此这个问题部分没有实际意义。至于“最佳实践”,没有一个:您只需使用正确的操作符即可。一般来说,人们赞成||
超过||
的布尔操作数,因为你可以确定它不会产生不必要的副作用。
答案 1 :(得分:44)
当与布尔操作数一起使用时,|
运算符与||
一样是逻辑运算符,但区别在于||
运算符执行短路评估和|
运营商没有。
这意味着始终使用|
运算符计算第二个操作数,但使用||
运算符时,仅在第一个操作数的计算结果为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,则无需计算第二个操作数以获得结果。此外,很多人(显然)不知道你可以将|
运算符与布尔操作数一起使用,因此当他们在代码中以这种方式使用它时会感到困惑。
答案 2 :(得分:10)
他们不一样。一个是按位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。如果按位OR的结果高于= 0x0001,则意味着在位域中没有打开位,除了可能第一位(0x0001),但你无法确定是否第一位位是打开的,因为它被屏蔽了。
有一个相应的&amp;&amp;和&amp;,它是逻辑AND和按位AND。他们有类似的行为。
您可以使用
if ((bitfield & 0x0001) == 0x0001) { ... }
查看第一位是否在位域中打开。
编辑:我不敢相信我已经为此投了票!答案 3 :(得分:5)
答案很好,但我要补充一点,如果左侧表达式为||
,则不评估true
的右侧表达式。如果评估术语是a)表现密集型或b)产生副作用(罕见),请记住这一点。
答案 4 :(得分:5)
与目前为止的大多数答案不同,其意思是不与C ++完全相同。
对于评估为布尔值的任何两个表达式A和B,A || B和A | B几乎做同样的事情。
A | B评估 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#中。
答案 5 :(得分:4)
|是一个按位OR运算符(数字,整数)。它通过将数字转换为二进制并为每个相应的数字执行OR来工作。然后,数字已经在计算机中以二进制形式表示,因此在运行时不会真正发生这种转换;)
||是一个逻辑OR运算符(布尔值)。它只适用于真值和假值。
答案 6 :(得分:3)
以下内容适用于C / C ++,因为它没有对布尔值的第一类支持,它将每个表达式都用“on”位处理为true,否则为false。实际上,如果x和y是数字类型,则以下代码在C#或Java中不起作用。
if (x | y)
所以上面代码的显式版本是:
if ( (x | y) != 0)
在C中,任何对其有“On”位的表达式都会导致为真
int i = 8;
if(i)//在C中有效,结果为真
int joy = -10;
if(joy)//在C中使用vaild,结果为true
现在,回到C#
如果x和y是数字类型,则代码:如果(x | y)不起作用。你试过编译吗?它不会起作用
但是对于你的代码,我可以假设x和y都是布尔类型的,所以它会起作用,所以它们之间的区别是和||对于布尔类型,||是短路的,|不是。以下输出:
static void Main()
{
if (x | y)
Console.WriteLine("Get");
Console.WriteLine("Yes");
if (x || y)
Console.WriteLine("Back");
Console.ReadLine();
}
static bool x
{
get { Console.Write("Hey"); return true; }
}
static bool y
{
get { Console.Write("Jude"); return false; }
}
是:
HeyJudeGet
Yes
HeyBack
裘德不会被打印两次,||是一个布尔运算符,许多C派生语言布尔运算符短路,如果布尔表达式被短路,它们的性能会更高。
至于外行术语,当你说短路时,例如在||中(或运算符),如果第一个表达式已经为真,则无需计算第二个表达式。示例:if(answer =='y'|| answer =='Y'),如果用户按小y,则程序不需要计算第二个表达式(answer =='Y')。这是短路。
在上面的示例代码中,X为真,所以Y在||上操作员不会被进一步评估,因此没有第二个“裘德”输出。
即使X和Y是布尔类型,也不要在C#中使用这种代码: if(x | y)。没有表现。
答案 7 :(得分:2)
第一个按位运算符处理两个数值,结果为第三个。
如果你有二进制变量
a = 0001001b;
b = 1000010b;
然后
a | b == 1001011b;
也就是说,如果在任一操作数中它也是1,则结果中的位为1。 (为清楚起见,我的例子使用了8位数字)
“double pipe”||是一个逻辑OR运算符,它接受两个布尔值并产生第三个。
答案 8 :(得分:2)
不以任何方式,形状或形式钻研细节,这里是真正的外行的版本。
想想“|”在英语中直接“或”;想到“||”英语中的“或其他”。
同样想到“&amp;”英语中的“和”;想到“&amp;&amp;”在英语中也是“和”。
如果你使用这些术语自己阅读表达,它们通常会更有意义。
答案 9 :(得分:2)
强烈建议您阅读Dotnet Mob的this文章
对于OR逻辑运算,如果它的任何操作数被评估为true,那么 整个表达式被评估为真
这是什么||运算符 - 它在发现真实时跳过剩余的评估。而|运算符评估它的完整操作数以评估整个表达式的值。
if(true||Condition1())//it skip Condition1()'s evaluation
{
//code inside will be executed
}
if(true|Condition1())//evaluates Condition1(), but actually no need for that
{
//code inside will be executed
}
最好使用逻辑运算符的短路版本无论是OR(||)还是AND(&amp;&amp;)运算符。
<小时/> 请考虑以下代码段
int i=0;
if(false||(++i<10))//Now i=1
{
//Some Operations
}
if(true||(++i<10))//i remains same, ie 1
{}
此效果称为 副作用 ,实际上在短路逻辑运算符的表达式右侧看到
答案 10 :(得分:1)
虽然已经说过并且回答正确但我认为我会添加一个真正的外行答案,因为很多时候这就是我在这个网站上的感觉:)。另外,我将添加&amp;的例子。 vs.&amp;&amp;因为它是相同的概念
<强> | vs ||
基本上你倾向于使用||当你只想评估第二部分时,如果它的第一部分为FALSE。所以这个:
if (func1() || func2()) {func3();}
与
相同if (func1())
{
func3();
}
else
{
if (func2()) {func3();}
}
这可能是节省处理时间的一种方法。如果func2()需要很长时间来处理,如果func1()已经为真,你就不想这样做。
<强>&安培; vs&amp;&amp;
在&amp; vs.&amp;&amp;这是类似的情况,你只评估第二部分,如果第一部分是真的。例如:
if (func1() && func2()) {func3();}
与
相同if (func1())
{
if (func2()) {func3();}}
}
这可能是必要的,因为func2()可能依赖于func1()首先为真。如果您使用&amp;和func1()评估为false,&amp;无论如何都会运行func2(),这可能会导致运行时错误。
Jeff the Layman