在finally块上使用未分配的局部变量

时间:2013-12-11 14:39:19

标签: c# try-catch local-variables unassigned-variable

此示例中的i何时可以取消分配?

int i;
try
{
    i = 2;
}
catch
{
    i = 3;
}
finally
{
    string a = i.ToString();
}

4 个答案:

答案 0 :(得分:6)

例如,你可以在i = 2次运行之前得到一个ThreadAbortException。无论如何,C#编译器不是特别聪明,所以很容易愚弄像上面这样的人为例子。它不必识别所有情况,如果它不确定它被分配,即使你确定,它也会抱怨。

编辑:我的第一次假设有点快。所以要改进它,这就是我的想法。代码保证按顺序运行,或者如果发生异常,它将跳转到处理程序。因此,如果在此之前发生异常,则i = 2可能无法运行。我仍然声称ThreadAbortException是导致这种情况发生的几个原因之一,即使你没有可能产生异常的代码。通常,如果您有任意数量的异常处理程序,则编译器无法预先知道将运行哪个异常处理程序。所以它不会试图对此做出任何假设。它可能知道如果1)只有1个catch块而2)它是无类型的,那么,只有这样,才能保证一个catch块运行。或者,如果有多个catch处理程序,并且您在每个处理程序中分配了变量,它也可以工作,但我想编译器也不关心它。看起来很简单,这是一个特殊情况,C#编译器团队倾向于忽略这些特殊情况。

答案 1 :(得分:2)

使用您发布的示例极不可能发生这种情况。但是,在这种情况下,compliler会“有用”。正如Hadas所说,只需将i初始化为0。

答案 2 :(得分:2)

有许多代码示例可以编写,其中可以证明分配了一个变量,但编译器根本无法证明它是明确分配的。

考虑一下这个更简单的案例:

int i;
if ((bool)(object)true)
    i = 0;

Console.WriteLine(i);

这种情况显然不可能永远访问未分配的i,但它不会编译。

在一般情况下,编译器也无法解决此问题。在某些情况下,它可以证明变量肯定没有明确分配,并且有些情况下它可以证明它肯定 分配,但也有一些情况,它只是不知道任何一种方式。在那些情况下,它选择失败,因为它看到一些误报错误,而不是假阴性。

详细说明您的具体案例;你说如果在trycatch块中分配了一个变量,它就是明确分配的。虽然对于您的特定代码可能也是如此,但在一般情况下肯定不是这样。您需要考虑catch块未处理的异常(即使在您的情况下,未指定任何内容,也不会捕获堆栈溢出或内存不足等异常),您需要考虑catch块本身抛出异常(同样,在你的情况下不会发生,但编译器需要证明编译代码)。

答案 3 :(得分:0)

我认为如果你看一下除了原语之外的其他类型会有所帮助。考虑:

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();
   ...
}

因此,在这段代码中,任何一个执行分支都没有字典保证。您需要考虑两个(至少)分支:try-finally分支和try-catch分支。由于函数" getIntFromFunctionThatWillThrow"将要抛出(看看我在那里做了什么?)即使我稍后尝试使用它,我也会被取消分配。但是,这不是在运行之后才能识别的东西,就像我不知道如果我没有关于ed成员的内部信息,这将会进入哪个代码段。所以编译器不知道我将成为什么样的价值。它只知道它存在,并且是int类型。

如果这是一个问题,修复是将i设置为初始值,这将抑制错误。

我希望这有点帮助!