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

i在这个例子中什么时候可以取消分配?

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

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

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

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

有很多代码样本可以编写,其中可以certificate分配了一个变量,但编译器根本无法certificate它是明确赋值的。

只考虑这个更简单的情况:

 int i; if ((bool)(object)true) i = 0; Console.WriteLine(i); 

对于那种情况来说,也可能无法访问未分配的i ,但它不会编译。

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

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

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

 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设置为初始值,这将抑制错误。

我希望这有点帮助!