也许我错过了一些明显的东西。请考虑以下代码:
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 可能无法初始化?
答案 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}},因此没有定义的值可供阅读。