为什么如果我写
void Main(){字符串值 = @"C:";if (!string.IsNullOrEmpty(value)) {字符串 sDirectory = Path.GetDirectoryName(value);}}它编译.
如果我写了
void Main(){字符串值 = @"C:";if (!string.IsNullOrEmpty(value))字符串 sDirectory = Path.GetDirectoryName(value);}不是吗?
很明显,从纯函数的角度来看,第二个示例中的变量声明是无用的,但是为什么它神奇地在第一 示例,所以?
两个示例生成的 IL 代码完全相同.
IL_0000: ldstr "C:"IL_0005:stloc.0IL_0006: ldloc.0IL_0007:调用 System.String.IsNullOrEmptyIL_000C:brtrue.s IL_0015IL_000E: ldloc.0IL_000F:调用 System.IO.Path.GetDirectoryName
忘记说明为第二种情况生成 IL 代码(因此不可编译的情况),在没有 string sDirectory 的情况下编译就足够了=
解决方案if 语句的产生式在 C# 规范的第 8.7.1 节中,它是这样的:
if 语句:if ( boolean-expression ) 嵌入语句if ( boolean-expression ) 嵌入语句 else 嵌入语句C# 规范第 8 节的开头明确谈到了embedded-statement 产生式,然后给出了它的规范:
嵌入语句:堵塞空语句表达式语句选择声明迭代语句跳转语句尝试语句检查语句未经检查的语句锁定语句使用语句产量声明嵌入式语句非终结符用于出现在其他语句中的语句.使用嵌入语句而不是语句排除了在这些上下文中使用声明语句和标记语句.例子
void F(bool b) {如果 (b)国际我= 44;}导致编译时错误,因为 if 语句需要嵌入语句而不是 if 分支的语句.如果允许使用此代码,则将声明变量 i,但永远无法使用它.但是请注意,通过将 i 的声明放在块中,该示例是有效的.
请注意,赋值算作表达式语句 - 但局部变量声明不算.(这是一个声明语句,如第 8.5 节所述.)
就设计决策而言,声明一个您随后无法使用的变量是没有意义的 - 所以编译器阻止您这样做是好的.
Why if I write
void Main() { string value = @"C:"; if (!string.IsNullOrEmpty(value)) { string sDirectory = Path.GetDirectoryName(value); } }it compiles.
And in case if I write
void Main() { string value = @"C:"; if (!string.IsNullOrEmpty(value)) string sDirectory = Path.GetDirectoryName(value); }It doesn't ?
It's clear that from pure functional point of view the declaration of the variable in the second example is useless, but why it magically becomes usefull in first example, so ?
The IL code produced by both examples is exactly the same.
IL_0000: ldstr "C:" IL_0005: stloc.0 IL_0006: ldloc.0 IL_0007: call System.String.IsNullOrEmpty IL_000C: brtrue.s IL_0015 IL_000E: ldloc.0 IL_000F: call System.IO.Path.GetDirectoryNameEDIT:
Forgot to mantion that to produce the IL code for the second case (so the case which is not compilable), it's enough to compile without string sDirectory =
解决方案The production for an if statement is in section 8.7.1 of the C# spec, and it goes like this:
if-statement: if ( boolean-expression ) embedded-statement if ( boolean-expression ) embedded-statement else embedded-statementThe start of section 8 of the C# spec explicitly talks about the embedded-statement production after giving the specification for it:
embedded-statement: block empty-statement expression-statement selection-statement iteration-statement jump-statement try-statement checked-statement unchecked-statement lock-statement using-statement yield-statementThe embedded-statement nonterminal is used for statements that appear within other statements. The use of embedded-statement rather than statement excludes the use of declaration statements and labeled statements in these contexts. The example
void F(bool b) { if (b) int i = 44; }results in a compile-time error because an if statement requires an embedded-statement rather than a statement for its if branch. If this code were permitted, then the variable i would be declared, but it could never be used. Note, however, that by placing i’s declaration in a block, the example is valid.
Note that an assignment counts as an expression-statement - but a local variable declaration doesn't. (That's a declaration-statement, as in section 8.5.)
In terms of a design decision, it makes no sense to declare a variable that you can't then use - so it's good that the compiler stops you from doing it.
更多推荐
为什么这个编译错误
发布评论