C# 是否保证分支嵌套表达式的求值顺序?
Does C# guarantee evaluation order of branched nested expressions?
C# 显然可以处理嵌套和链式表达式。
如果嵌套 and/or 链接是线性的,那么很明显表达式的计算顺序是:
Foo(Bar(Baz().Bop()))
只能按以下顺序求值:
Baz()
Bop()
Bar()
Foo()
但是如果嵌套不是线性的呢?考虑:Foo(Baz()).Bar(Bop())
显然以下必须全部为真:
Baz
在 Foo
之前
Foo
在 Bar
之前
Bop
在 Bar
之前
但尚不清楚 Bop
的确切评估时间。
以下任何一项都是可行的订单:
- 可能性 #1
Bop()
Baz()
Foo()
Bar()
- 可能性 #2
Baz()
Bop()
Foo()
Bar()
- 可能性#3
Baz()
Foo()
Bop()
Bar()
我的直觉是第三个选项可能是正确的。也就是说,它将在开始评估 .Bar(Bop())
的 any 之前完全评估 Foo(Baz())
虽然我当然可以测试个别情况以查看会发生什么,但这并不能告诉我我的猜测是否总是是真的?
但我的问题是:
分支嵌套表达式的求值顺序是定义为C#语言规范的一部分,还是留给编译器的情况判断?
如果不是,是否至少知道它是确定性的?
您会在 Section 11 of the specification 中找到答案。
具体来说,11.6.6 Function member invocation 表示:
The run-time processing of a function member invocation consists of the following steps, where M
is the function member and, if M
is an instance member, E
is the instance expression:
...
E
is evaluated. If this evaluation causes an exception, then no further steps are executed.
- The argument list is evaluated as described in §11.6.2.
因此,给定表达式 E.M(A)
,E
在 A
被求值之前被完全求值。
对于 Foo(Baz()).Bar(Bop())
的情况,如果我们查看 Bar
的评估(所以 E
是 Foo(Baz())
,M
是 Bar
并且参数列表是 Bop()
),这意味着 Foo
(E
) 必须在 Bop
(参数列表)被评估之前被完全评估,这意味着“可能性 #3”是正确的。
还有11.6.2.3 Run-time evaluation of argument lists:
During the run-time processing of a function member invocation (§11.6.6), the expressions or variable references of an argument list are evaluated in order, from left to right
所以在表达式 M(A, B)
中,A
在 B
被求值之前被完全求值。
C# 显然可以处理嵌套和链式表达式。 如果嵌套 and/or 链接是线性的,那么很明显表达式的计算顺序是:
Foo(Bar(Baz().Bop()))
只能按以下顺序求值:
Baz()
Bop()
Bar()
Foo()
但是如果嵌套不是线性的呢?考虑:Foo(Baz()).Bar(Bop())
显然以下必须全部为真:
Baz
在Foo
之前
Foo
在Bar
之前
Bop
在Bar
之前
但尚不清楚 Bop
的确切评估时间。
以下任何一项都是可行的订单:
- 可能性 #1
Bop()
Baz()
Foo()
Bar()
- 可能性 #2
Baz()
Bop()
Foo()
Bar()
- 可能性#3
Baz()
Foo()
Bop()
Bar()
我的直觉是第三个选项可能是正确的。也就是说,它将在开始评估 .Bar(Bop())
Foo(Baz())
虽然我当然可以测试个别情况以查看会发生什么,但这并不能告诉我我的猜测是否总是是真的?
但我的问题是: 分支嵌套表达式的求值顺序是定义为C#语言规范的一部分,还是留给编译器的情况判断?
如果不是,是否至少知道它是确定性的?
您会在 Section 11 of the specification 中找到答案。
具体来说,11.6.6 Function member invocation 表示:
The run-time processing of a function member invocation consists of the following steps, where
M
is the function member and, ifM
is an instance member,E
is the instance expression:
...
E
is evaluated. If this evaluation causes an exception, then no further steps are executed.- The argument list is evaluated as described in §11.6.2.
因此,给定表达式 E.M(A)
,E
在 A
被求值之前被完全求值。
对于 Foo(Baz()).Bar(Bop())
的情况,如果我们查看 Bar
的评估(所以 E
是 Foo(Baz())
,M
是 Bar
并且参数列表是 Bop()
),这意味着 Foo
(E
) 必须在 Bop
(参数列表)被评估之前被完全评估,这意味着“可能性 #3”是正确的。
还有11.6.2.3 Run-time evaluation of argument lists:
During the run-time processing of a function member invocation (§11.6.6), the expressions or variable references of an argument list are evaluated in order, from left to right
所以在表达式 M(A, B)
中,A
在 B
被求值之前被完全求值。