在Try-Catch-Finally中访问之前,可能无法初始化C#本地变量

时间:2018-06-15 20:37:46

标签: c# local-variables try-catch-finally

也许我错过了一些明显的东西。请考虑以下代码:

Sub pre()

Dim i As Long: i = 2

Dim rex As Variant

For rex = -10 To 10 Step 0.001

Cells(i, 47) = rex
i = i + 1
Next rex
End Sub

此处编译器显示众所周知的错误 CS0165:使用未分配的局部变量'str'。我知道我可以通过string str; try { str = ""; } catch (Exception) { str = ""; } finally { Console.WriteLine(str); } Console.WriteLine(str); //this compiles 来解决这个问题。但是,哪个执行路径 str 可能无法初始化?

1 个答案:

答案 0 :(得分:2)

提供另一种与线程无关的方式:编译器以这种方式行为,因为这是指定语言的方式

来自ECMA C#5规范部分10.4.4.16:

  

Try-catch-finally语句

     

对表单的try-catch-finally语句进行明确的赋值分析:

try try-block
catch ( … ) catch-block-1
…
catch ( … ) catch-block-n
finally finally-block
     完成

就好像该语句是一个包含try-catch语句的try-finally语句:

try {
  try try-block
  catch ( … ) catch-block-1
   …
  catch ( … ) catch-block-n
}
finally finally-block

那么try-finally语句如何在明确赋值方面起作用?这是10.4.4.16节中的内容:

  

对于表单的try语句 stmt

     

尝试try-block finally finally-block

     
      
  • ...
  •   
  • finally-block 开头的 v 的明确赋值状态与 v 的明确赋值状态相同of stmt
  •   

那么在你的情况下这意味着什么?在语句开头,您的变量str并未明确分配...因此,根据这些规则,它的在{{1}的开头没有明确分配阻止。

现在,为什么语言是这样设计的?这个问题略有不同。我不认为这与线程有任何关系。该语言通常假定任何可以抛出异常。变量明确分配的唯一方法是为其分配值并完成分配而不抛出异常。即使在赋值之前发生异常,也可能发生的任何代码路径都不能被认为是明确赋值变量。

举个简单的例子,假设我们将您的代码更改为:

finally

此时,string str; try { str = MethodThatThrowsAnException(); } catch (Exception) { str = MethodThatThrowsAnException(); } finally { Console.WriteLine(str); } 未明确分配似乎并不奇怪。这只是因为它分配了一个字符串文字,看起来它可能会失败。但我可以想象,即使分配字符串文字失败,如果它是第一次看到字符串常量,并且它需要分配一个str对象......分配可能会失败。然后还有所有其他方法可以抛出异常,包括线程被中止。

所有这一切都意味着:

  • String块中的第一个语句可能会抛出异常
  • try块中的第一个语句可能会抛出异常

在那种情况下 - 无论如何发生,以及它是否与线程有关(例如,可能是分配失败) - 您将无法执行任何{{ {1}},因此没有定义的值可供阅读。