C# 逻辑顺序和编译器行为

发布于 2024-07-04 02:35:41 字数 496 浏览 7 评论 0原文

在 C# 中(也可以随意回答其他语言),运行时计算逻辑语句的顺序是什么?

示例:

DataTable myDt = new DataTable();
if (myDt != null && myDt.Rows.Count > 0)
{
    //do some stuff with myDt
}

运行时首先评估哪个语句 -

myDt != null

或:

myDt.Rows.Count > 0

编译器是否会向后评估该语句? 也许当涉及“OR”运算符时?


& 被称为逻辑按位运算符,并且将始终计算所有子表达式

何时使用按位运算符而不是“短路布尔值”的一个很好的例子是什么?

In C#, (and feel free to answer for other languages), what order does the runtime evaluate a logic statement?

Example:

DataTable myDt = new DataTable();
if (myDt != null && myDt.Rows.Count > 0)
{
    //do some stuff with myDt
}

Which statement does the runtime evaluate first -

myDt != null

or:

myDt.Rows.Count > 0

?

Is there a time when the compiler would ever evaluate the statement backwards? Perhaps when an "OR" operator is involved?


& is known as a logical bitwise operator and will always evaluate all the sub-expressions

What is a good example of when to use the bitwise operator instead of the "short-circuited boolean"?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(18

雪若未夕 2024-07-11 02:35:41

当一切都在线时,它们将从左到右执行。

当事物嵌套时,它们是从内到外执行的。 这可能看起来很令人困惑,因为通常“最里面”的内容位于该行的右侧,因此看起来像是在向后移动......

例如,

a = Foo( 5, GetSummary( "Orion", GetAddress("Orion") ) );

事情发生如下:

  • 使用文字调用 GetAddress "Orion"
  • 的结果
  • 使用文字 "Orion" 调用 GetSummary 以及 GetAddress调用 Foo< /code> 带有文字 5GetSummary 的结果
  • 将此值分配给 a

When things are all in-line, they're executed left-to-right.

When things are nested, they're executed inner-to-outer. This may seem confusing as usually what's "innermost" is on the right-hand side of the line, so it seems like it's going backwards...

For example

a = Foo( 5, GetSummary( "Orion", GetAddress("Orion") ) );

Things happen like this:

  • Call GetAddress with the literal "Orion"
  • Call GetSummary with the literal "Orion" and the result of GetAddress
  • Call Foo with the literal 5 and the result of GetSummary
  • Assign this value to a
も让我眼熟你 2024-07-11 02:35:41

我意识到这个问题已经得到解答,但我想补充一些与该主题相关的信息。

在 C++ 等语言中,您实际上可以重载 && 的行为。 和 || 运营商,强烈建议您不要这样做。 这是因为当您重载此行为时,您最终会强制对操作的两侧进行评估。 这做了两件事:

  1. 它打破了惰性求值机制,因为重载是一个必须调用的函数,因此两个参数在调用该函数之前都会被求值。
  2. 不保证所述参数的评估顺序,并且可能是特定于编译器的。 因此,对象的行为方式与问题/先前答案中列出的示例不同。

有关详细信息,请阅读 Scott Meyers 的书更高效的 C++。 干杯!

I realise this question has already been answered, but I'd like to throw in another bit of information which is related to the topic.

In languages, like C++, where you can actually overload the behaviour of the && and || operators, it is highly recommended that you do not do this. This is because when you overload this behaviour, you end up forcing the evaluation of both sides of the operation. This does two things:

  1. It breaks the lazy evaluation mechanism because the overload is a function which has to be invoked, and hence both parameters are evaluated before calling the function.
  2. The order of evaluation of said parameters isn't guaranteed and can be compiler specific. Hence the objects wouldn't behave in the same manner as they do in the examples listed in the question/previous answers.

For more info, have a read of Scott Meyers' book, More Effective C++. Cheers!

江南月 2024-07-11 02:35:41

“C#:从左到右,如果找到匹配项(评估结果为 true),则处理停止。”

僵尸羊错了。

问题是关于 && 运算符,而不是 || 操作员。

在 && 的情况下 如果发现 FALSE,评估将停止。

在 || 的情况下 如果找到 TRUE,则评估停止。

"C# : Left to right, and processing stops if a match (evaluates to true) is found."

Zombie sheep is wrong.

The question is about the && operator, not the || operator.

In the case of && evaluation will stop if a FALSE is found.

In the case of || evaluation stops if a TRUE is found.

攀登最高峰 2024-07-11 02:35:41

C#:从左到右,如果发现不匹配(计算结果为 false),则处理停止。

C# : Left to right, and processing stops if a non-match (evaluates to false) is found.

南城追梦 2024-07-11 02:35:41

vb.net

if( x isNot Nothing AndAlso x.go()) then
  1. 评估是从左到右进行的
  2. AndAlso 运算符确保只有左侧为 TRUE 时,才会评估右侧(非常重要,因为 ifx 没什么用处) x.go 会崩溃)

你可以在 vb 中使用 And 而不是 AndAlso。 在这种情况下,左侧也会首先被评估,但无论结果如何,右侧都会被评估。

最佳实践:始终使用 AndAlso,除非您有充分的理由不这样做。


在后续中有人问为什么或何时有人会使用 And 而不是 AndAlso(或 & 而不是 &&):
下面是一个示例:

if ( x.init() And y.init()) then
   x.process(y)
end 
y.doDance()

在本例中,我想要初始化 X 和 Y。必须初始化 Y 才能使 y.DoDance 能够执行。 但是,在 init() 函数中,我还做了一些额外的事情,例如检查套接字是否打开,并且只有当效果正常时,对于两者,我应该继续执行 x.process (y)。

同样,在 99% 的情况下这可能是不需要的,而且也不优雅,这就是为什么我说默认应该使用 AndAlso

vb.net

if( x isNot Nothing AndAlso x.go()) then
  1. Evaluation is done left to right
  2. AndAlso operator makes sure that only if the left side was TRUE, the right side will be evaluated (very important, since ifx is nothing x.go will crash)

You may use And instead ofAndAlso in vb. in which case the left side gets evaluated first as well, but the right side will get evaluated regardless of result.

Best Practice: Always use AndAlso, unless you have a very good reason why not to.


It was asked in a followup why or when would anyone use And instead of AndAlso (or & instead of &&):
Here is an example:

if ( x.init() And y.init()) then
   x.process(y)
end 
y.doDance()

In this case, I want to init both X and Y. Y must be initialized in order for y.DoDance to be able to execute. However, in the init() function I am doing also some extra thing like checking a socket is open, and only if that works out ok, for both, I should go ahead and do the x.process(y).

Again, this is probably not needed and not elegant in 99% of the cases, that is why I said that the default should be to use AndAlso.

酒与心事 2024-07-11 02:35:41

@shsteimer

谦虚所指的概念是运算符重载。 在声明中:
...
首先评估 A,如果评估结果为 false,则永远不会评估 B。 这同样适用于

That's not 运算符重载。 运算符重载是一个术语,用于让您定义运算符的自定义行为,例如 *、+、= 等。

这将让您编写自己的“Log”类,然后执行

a = new Log(); // Log class overloads the + operator
a + "some string"; // Call the overloaded method - otherwise this wouldn't work because you can't normally add strings to objects.

此操作

a() || b() // be never runs if a is true

实际上称为 短路评估

@shsteimer

The concept modesty is referring to is operator overloading. in the statement:
...
A is evaluated first, if it evaluates to false, B is never evaluated. The same applies to

That's not operator overloading. Operator overloading is the term given for letting you define custom behaviour for operators, such as *, +, = and so on.

This would let you write your own 'Log' class, and then do

a = new Log(); // Log class overloads the + operator
a + "some string"; // Call the overloaded method - otherwise this wouldn't work because you can't normally add strings to objects.

Doing this

a() || b() // be never runs if a is true

is actually called Short Circuit Evaluation

冷︶言冷语的世界 2024-07-11 02:35:41

请注意,&& 之间存在差异。 和& 关于评估您的表达的程度。

&& 被称为短路布尔 AND,并且正如其他人在此指出的那样,如果可以在计算所有子表达式之前确定结果,则将提前停止。

& 被称为逻辑按位运算符,并且将始终计算所有子表达式。

因此:

if (a() && b())

仅当 a 返回 true 时才会调用 b

但是,这:

if (a() & b())

将始终调用 ab,即使调用 a 的结果为 false,因此已知为 false,无论调用 b 的结果如何。

|| 也存在同样的差异 和 | 运营商。

Note that there is a difference between && and & regarding how much of your expression is evaluated.

&& is known as a short-circuited boolean AND, and will, as noted by others here, stop early if the result can be determined before all the sub-expressions are evaluated.

& is known as a logical bitwise operator and will always evaluate all the sub-expressions.

As such:

if (a() && b())

Will only call b if a returns true.

however, this:

if (a() & b())

Will always call both a and b, even though the result of calling a is false and thus known to be false regardless of the result of calling b.

This same difference exists for the || and | operators.

执着的年纪 2024-07-11 02:35:41

ZombieSheep 完全正确。 唯一可能等待的“问题”是,只有当您使用 && 时,这才是正确的。 操作员。 当使用 & 运算符,每次都会计算两个表达式,无论一个或两个表达式的计算结果是否为 false。

if (amHungry & whiteCastleIsNearby)
{
   // The code will check if White Castle is nearby
   // even when I am not hungry
}

if (amHungry && whiteCastleIsNearby)
{
   // The code will only check if White Castle is nearby
   // when I am hungry
}

ZombieSheep is dead-on. The only "gotcha" that might be waiting is that this is only true if you are using the && operator. When using the & operator, both expressions will be evaluated every time, regardless if one or both evaluate to false.

if (amHungry & whiteCastleIsNearby)
{
   // The code will check if White Castle is nearby
   // even when I am not hungry
}

if (amHungry && whiteCastleIsNearby)
{
   // The code will only check if White Castle is nearby
   // when I am hungry
}
死开点丶别碍眼 2024-07-11 02:35:41

左边的,如果为空则停止。

编辑:在 vb.net 中,它将评估两者并可能引发错误,除非您使用 AndAlso

The left one, then stops if it is null.

Edit: In vb.net it will evaluate both and possibly throw an error, unless you use AndAlso

怀念你的温柔 2024-07-11 02:35:41

谦虚所指的概念是运算符重载。 在语句中:

if( A && B){
    // do something
}

首先评估 A,如果评估为 false,则永远不会评估 B。 这同样适用于

if(A || B){
    //do something
}

首先评估 A,如果评估为 true,则永远不会评估 B。

这个概念,重载,适用于(我认为)所有 C 风格语言,以及许多其他语言。

The concept modesty is referring to is operator overloading. in the statement:

if( A && B){
    // do something
}

A is evaluated first, if it evaluates to false, B is never evaluated. The same applies to

if(A || B){
    //do something
}

A is evaluated first, if it evaluates to true, B is never evaluated.

This concept, overloading, applies to (i think) all of the C style languages, and many others as well.

甜味拾荒者 2024-07-11 02:35:41

有些语言有一些有趣的情况,其中表达式以不同的顺序执行。 我特别想到 Ruby,但我确信他们从其他地方(可能是 Perl)借用了它。

逻辑中的表达式将保持从左到右,但例如:

puts message unless message.nil?

上面将计算“message.nil?” 首先,如果它的计算结果为 false(除非它在条件为 false 而不是 true 时执行),则将执行“puts message”,它将 message 变量的内容打印到屏幕上。

有时,这是一种构建代码的有趣方式...我个人喜欢将它用于像上面这样的非常短的 1 行。

编辑:

为了更清楚一点,上面的内容与:

unless message.nil?
  puts message
end

Some languages have interesting situations where expressions are executed in a different order. I am specifically thinking of Ruby, but I'm sure they borrowed it from elsewhere (probably Perl).

The expressions in the logic will stay left to right, but for example:

puts message unless message.nil?

The above will evaluate "message.nil?" first, then if it evaluates to false (unless is like if except it executes when the condition is false instead of true), "puts message" will execute, which prints the contents of the message variable to the screen.

It's kind of an interesting way to structure your code sometimes... I personally like to use it for very short 1 liners like the above.

Edit:

To make it a little clearer, the above is the same as:

unless message.nil?
  puts message
end
习惯成性 2024-07-11 02:35:41

不,至少 C# 编译器不会向后工作(在 && 或 || 中)。 它是从左到右。

Nopes, at least the C# compiler doesn't work backwards (in either && or ||). It's left to right.

旧梦荧光笔 2024-07-11 02:35:41

我喜欢猎户座的回应。 我将添加两件事:

  1. 从左到右仍然首先适用
  2. 从内到外以确保在调用函数之前解析所有参数

假设我们有以下示例:

a = Foo(5, GetSummary("Orion", GetAddress("Orion")),
           GetSummary("Chris", GetAddress("Chris")));

这是执行顺序:

  1. GetAddress (“猎户座”)
  2. GetSummary(“猎户座”,...)
  3. GetAddress(“克里斯”)
  4. GetSummary(“克里斯”,.. .)
  5. Foo(...)
  6. 分配给 a

我无法谈论 C# 的法律要求(尽管在编写之前我确实使用 Mono 测试了类似的示例)这篇文章),但这个顺序在 Java 中是有保证的。

为了完整性(因为这也是一个与语言无关的线程),有一些语言,如 C 和 C++,除非存在序列点,否则无法保证顺序。 参考文献:12。 然而,在回答线程的问题时, &&|| 是 C++ 中的序列点(除非重载;另请参阅 OJ 的优秀答案)。 一些例子:

  • foo() && bar()
  • foo() & bar()

&& 情况下,保证 foo()bar() 之前运行(如果后者完全运行),因为 && 是一个序列点。 在 & 情况下,没有做出这样的保证(在 C 和 C++ 中),并且实际上 bar() 可以在 foo() 之前运行, 或相反亦然。

I like Orion's responses. I'll add two things:

  1. The left-to-right still applies first
  2. The inner-to-outer to ensure that all arguments are resolved before calling the function

Say we have the following example:

a = Foo(5, GetSummary("Orion", GetAddress("Orion")),
           GetSummary("Chris", GetAddress("Chris")));

Here's the order of execution:

  1. GetAddress("Orion")
  2. GetSummary("Orion", ...)
  3. GetAddress("Chris")
  4. GetSummary("Chris", ...)
  5. Foo(...)
  6. Assigns to a

I can't speak about C#'s legal requirements (although I did test a similar example using Mono before writing this post), but this order is guaranteed in Java.

And just for completeness (since this is a language-agnostic thread as well), there are languages like C and C++, where the order is not guaranteed unless there is a sequence point. References: 1, 2. In answering the thread's question, however, && and || are sequence points in C++ (unless overloaded; also see OJ's excellent answer). So some examples:

  • foo() && bar()
  • foo() & bar()

In the && case, foo() is guaranteed to run before bar() (if the latter is run at all), since && is a sequence point. In the & case, no such guarantee is made (in C and C++), and indeed bar() can run before foo(), or vice versa.

风情万种。 2024-07-11 02:35:41

什么时候使用按位运算符而不是“短路布尔值”的一个很好的例子是什么?

假设您有标志,例如文件属性。 假设您将 READ 定义为 4,将 WRITE 定义为 2,将 EXEC 定义为 1。在二进制中,即:

READ  0100  
WRITE 0010  
EXEC  0001

每个标志都设置了一位,并且每一位都是唯一的。 按位运算符可让您组合这些标志:

flags = READ & EXEC; // value of flags is 0101

What is a good example of when to use the bitwise operator instead of the "short-circuited boolean"?

Suppose you have flags, say for file attributes. Suppose you've defined READ as 4, WRITE as 2, and EXEC as 1. In binary, that's:

READ  0100  
WRITE 0010  
EXEC  0001

Each flag has one bit set, and each one is unique. The bitwise operators let you combine these flags:

flags = READ & EXEC; // value of flags is 0101
过期以后 2024-07-11 02:35:41

我听说过编译器向后工作,但我不确定这有多真实。

I have heard somewhere that compilers work backwards, but I am unsure how true this is.

把时间冻结 2024-07-11 02:35:41

您使用 & 当您特别想要计算所有子表达式时,很可能是因为它们具有您想要的副作用,即使最终结果将是 false 并因此不执行您的 then > if 语句的一部分。

请注意 & 和 | 适用于按位掩码和布尔值,而不仅仅是按位运算。 它们被称为按位,但它们是为 C# 中的整数和布尔数据类型定义的。

You use & when you specifically want to evaluate all the sub-expressions, most likely because they have side-effects you want, even though the final result will be false and thus not execute your then part of your if-statement.

Note that & and | operates for both bitwise masks and boolean values and is not just for bitwise operations. They're called bitwise, but they are defined for both integers and boolean data types in C#.

写下不归期 2024-07-11 02:35:41

@csmba

在后续中有人问为什么或何时有人会使用 And 而不是 AndAlso(或 & 而不是 &&):这是一个示例:

if ( x.init() 和 y.init()) then 
     x.进程(y) 
  结尾  
  y.doDance() 
  

在本例中,我想初始化 X 和 Y。必须初始化 Y 才能使 y.DoDance 能够执行。 但是,在 init() 函数中,我还做了一些额外的事情,例如检查套接字是否打开,并且只有当效果正常时,对于两者,我才应该继续执行 x.process(y)。

我相信这相当令人困惑。 尽管您的示例有效,但它不是使用 And 的典型情况(我可能会以不同的方式编写它以使其更清晰)。 And(大多数其他语言中的&)实际上是按位与运算。 您可以使用它来计算位操作,例如删除标志位或屏蔽和测试标志:

Dim x As Formatting = Formatting.Bold Or Formatting.Italic
If (x And Formatting.Italic) = Formatting.Italic Then
    MsgBox("The text will be set in italic.")
End If

@csmba:

It was asked in a followup why or when would anyone use And instead of AndAlso (or & instead of &&): Here is an example:

if ( x.init() And y.init()) then
   x.process(y)
end 
y.doDance()

In this case, I want to init both X and Y. Y must be initialized in order for y.DoDance to be able to execute. However, in the init() function I am doing also some extra thing like checking a socket is open, and only if that works out ok, for both, I should go ahead and do the x.process(y).

I believe this is rather confusing. Although your example works, it's not the typical case for using And (and I would probably write this differently to make it clearer). And (& in most other languages) is actually the bitwise-and operation. You would use it to calculate bit operations, for example deleting a flag bit or masking and testing flags:

Dim x As Formatting = Formatting.Bold Or Formatting.Italic
If (x And Formatting.Italic) = Formatting.Italic Then
    MsgBox("The text will be set in italic.")
End If
山人契 2024-07-11 02:35:41

D 编程语言确实执行从左到右短路求值不允许 重载 && 和 '||' 运算符。

The D programming language Does do left-to-right evaluation with short circuiting and doesn't allow overloading of the && and '||' operators.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文