为什么这个编译错误

为什么我写

void Main() { string value = @"C:\"; if (!string.IsNullOrEmpty(value)) { string sDirectory = Path.GetDirectoryName(value); } } 

它汇编。

如果我写的话

 void Main() { string value = @"C:\"; if (!string.IsNullOrEmpty(value)) string sDirectory = Path.GetDirectoryName(value); } 

不是吗?

很明显,从纯粹的function观点来看, 第二个例子中变量的声明是无用的,但为什么它在第一个例子中神奇地变得有用,所以呢?

两个例子产生的IL代码完全相同

 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.GetDirectoryName 

编辑:

忘了为第二种情况生成IL代码(所以不能编译的情况),这就足以在没有string sDirectory =的情况下编译string sDirectory =

if语句的生成在C#规范的第8.7.1节中,它是这样的:

 if-statement: if ( boolean-expression ) embedded-statement if ( boolean-expression ) embedded-statement else embedded-statement 

在给出规范之后,C#规范第8节的开头明确地讨论了嵌入式语句的产生:

 embedded-statement: block empty-statement expression-statement selection-statement iteration-statement jump-statement try-statement checked-statement unchecked-statement lock-statement using-statement yield-statement 

嵌入语句非终结符用于出现在其他语句中的语句。 嵌入式语句而不是语句的使用排除了在这些上下文中使用声明语句和带标签的语句。 这个例子

 void F(bool b) { if (b) int i = 44; } 

导致编译时错误,因为if语句需要嵌入语句而不是if分支的语句。 如果允许这个代码,那么将声明变量i,但它永远不会被使用。 但请注意,通过将i的声明放在块中,该示例是有效的。

请注意,赋值计为表达式语句 – 但局部变量声明不计算。 (这是一份声明声明 ,如第8.5节所述。)

就设计决策而言,声明一个你不能使用的变量是没有意义的 – 所以编译器阻止你做这件事是好的

你的第二个表单试图使用有效的两个语句(一个变量声明和一个变量赋值),其中只能使用一个语句。 把它想象成:

 if (!string.IsNullOrEmpty(value)) string sDirectory; sDirectory = Path.GetDirectoryName(value); 

你可以看到这不会编译!

带括号的第一个版本声明了一个新的局部作用域,在其中声明了一个字符串变量,第二个版本没有 – 变量声明和赋值被解释为单个嵌入式语句,可能不包含变量声明,因此编译错误。

 string value = @"C:\"; if (!string.IsNullOrEmpty(value)) string sDirectory = Path.GetDirectoryName(value); 

第二个语句是被认为是一个嵌入式语句..如果你想在它周围的所谓的“代码块”包裹{}中使用sDirectory。 在我看来,你想要做的内联陈述会导致可读性差。

  string value = @"C:\"; string sDirectory = string.Empty; should be even better way to code.. if (!string.IsNullOrEmpty(value)) { sDirectory = Path.GetDirectoryName(value); } 

或这个

现在两个案例都应该编译

  string value = @"C:\"; string sDirectory = string.Empty; if (!string.IsNullOrEmpty(value)) sDirectory = Path.GetDirectoryName(value); 

我不确定C#,但其他语言就是这种情况:因为{}打开一个块,因此打开一个新的范围。 如果省略它们,那么变量将在Main的范围内声明,因此只会在某些时候声明,因此编译器之后不知道sDirectory是否存在。