Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/309.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 为什么会出现这种编译错误_C#_Compilation - Fatal编程技术网

C# 为什么会出现这种编译错误

C# 为什么会出现这种编译错误,c#,compilation,C#,Compilation,为什么我要写信 void Main() { string value = @"C:\"; if (!string.IsNullOrEmpty(value)) { string sDirectory = Path.GetDirectoryName(value); } } void Main() { string value = @"C:\"; if (!string.IsNullOrEmpty(value)

为什么我要写信

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);


}
它编译

万一我写信

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 (!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);

if
语句的生成在C#spec第8.7.1节中,如下所示:

if-statement:
    if   ( boolean-expression )   embedded-statement
    if   ( boolean-expression )   embedded-statement   else   embedded-statement
C#规范第8节的开头在给出了嵌入式语句的规范之后,明确地谈到了嵌入式语句的生成:

嵌入语句nonterminal用于出现在其他语句中的语句。使用嵌入式语句而不是语句排除了在这些上下文中使用声明语句和标记语句。榜样

void F(bool b) {
     if (b)
         int i = 44;
} 
导致编译时错误,因为if语句的if分支需要嵌入语句而不是语句。如果允许使用此代码,那么将声明变量i,但它永远不能使用。但是,请注意,通过将i的声明放在块中,示例是有效的

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


就设计决策而言,声明一个无法使用的变量是没有意义的——因此编译器阻止您这样做是好事。

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

为什么要创建一个立即消失的变量?这是在发行版还是调试模式下编译的?如果无法编译,如何获得第二个IL?@David:只需删除sDirectory并编译:)就会编辑帖子。可能的同意的副本,编译器在第二种情况下阻止我是绝对好的。我的问题是关于第一个和第二个的区别,但这可能会引出一个问题,为什么{}是完全可编译的情况。@Tigran:希望我的问题回答了区别部分-它们是不同类型的语句,其中一种可以作为嵌入语句,另一种不可以。正如我给David写的,这两种情况实际上都是无用的,编译器能够识别这一点,所以为什么选择其中一种而不选择另一种呢?为什么要把它们区别开来?这实际上是问题的根源。@Tigran:编译器能够在第一种情况下识别出您有一个未使用的局部变量,作为块的一部分-但这是一种语义分析,而不仅仅是语法分析。规范中说变量永远不可能被使用,这实际上并不十分正确<代码>如果(x)int i=M(out i)+i既可以写也可以读
i
;这样的局部变量声明非常奇怪,但却是合法的。准确地说,由初始值设定项的值确定的i的值永远不能使用。问题是,这两种情况都是无用的,编译器能够理解它,所以为什么选择一种而不是另一种呢。