本例中的i
何时可以取消分配?
int i;
try
{
i = 2;
}
catch
{
i = 3;
}
finally
{
string a = i.ToString();
}
例如,在i=2运行之前,您可以获得ThreadAbortException无论如何,C#编译器并不是特别聪明,所以很容易用上面这样的人为例子。它不必识别每一种情况,如果它不确定它是否被分配,即使你确定,它也会抱怨。
编辑:我的第一个假设有点快。因此,为了完善它,以下是我的想法。代码保证按顺序运行,或者如果发生异常,它将跳转到处理程序。因此,如果在此之前发生异常,i=2可能不会运行。我仍然声称ThreadAbortException是发生这种情况的少数原因之一,即使你没有可能产生异常的代码。通常,如果有任意数量的不同异常处理程序,编译器无法提前知道将运行哪一个。因此,它没有试图对此做出任何假设。它可以知道,如果1)只有一个catch块,2)它是无类型的,那么,而且只有这样,一个catchblock才能保证运行。或者,如果有多个catch处理程序,并且你在其中的每一个处理程序中都分配了变量,它也可以工作,但我想编译器也不在乎这一点。无论它看起来多么简单,它都是一种特殊情况,C#编译器团队倾向于忽略这些特殊情况。
您发布的示例不太可能发生这种情况。然而,在这种情况下,同谋者会"有所帮助"。正如Hadas所说,只需将i初始化为0即可。
有很多代码示例可以编写,其中可以证明变量被赋值,但编译器根本无法证明它被明确赋值。
只要考虑一下这个简单得多的例子:
int i;
if ((bool)(object)true)
i = 0;
Console.WriteLine(i);
事实证明,在这种情况下,也不可能访问未分配的i
,但它不会编译。
在一般情况下,编译器也不可能解决这个问题。在某些情况下,它可以证明变量肯定不是明确分配的,也有一些情况下,可以证明是分配的,但也有一些例子,它只是不知道任何一种方式。在这些情况下,它选择失败,因为它认为一些假阳性错误的危害比假阴性小。
多谈谈你的具体情况;你是说,如果在try
和catch
块中都分配了一个变量,那么它肯定是被分配的。虽然您的特定代码可能是这样,但在一般情况下肯定不是这样。您需要考虑catch
块没有处理的异常(即使在您的情况下,没有指定异常,也不会捕获堆栈溢出或内存不足等异常),您需要考虑catch块本身引发异常(同样,在您的例子中不会发生这种情况,但编译器需要证明这一点才能编译代码)。
我认为,如果您查看除基元之外的另一种类型,会有所帮助。考虑:
int i;
MyClass ed = new MyClass();
try
{
int newI = ed.getIntFromFunctionThatWillThrow();
i = newI;
}
catch (Exception e)
{
i = 3;
// do some abortion code.
}
finally
{
string a = i.ToString();
...
}
因此,在这个代码块中,对于任何一个执行分支都没有字典式的保证。您需要考虑两个(至少)分支:tryfinally分支和try-catch分支。由于函数"getIntFromFunctionThatWillThrow"将抛出(看到我在那里做了什么吗?),即使我稍后尝试使用它,我也会被取消分配。然而,直到运行时之后,这才被识别出来,就像我不知道如果我没有关于ed上成员的内部信息,这会进入代码的哪一部分。所以编译器不知道I会是什么值。它只知道它存在,并且是int类型的。
如果这是一个问题,修复方法是设置i一个初始值,这将抑制错误。
我希望这能有所帮助!