为什么会出现此编译错误
本文关键字:编译 错误 为什么 | 更新日期: 2023-09-27 18:20:06
为什么我要写
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);
}
不是吗?
很明显,从纯函数的角度来看,第二个示例中变量的声明是无用的,但为什么神奇地在第一个示例中变得有用呢?
两个示例生成的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 =
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
是否存在。