C# 局部变量在 Try-Catch-Finally 中访问之前可能不会初始化

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

也许我遗漏了一些明显的东西。考虑以下代码:

string str;
try
{
    str = "";
}
catch (Exception)
{
    str = "";
}
finally
{
    Console.WriteLine(str);
}
Console.WriteLine(str); //this compiles

这里编译器显示了众所周知的错误CS0165:使用未分配的局部变量“str”。我知道我可以通过执行 string str = null 来修复它。但是,str在哪个执行路径中可能没有被初始化呢?

最佳答案

提供另一种与线程无关的方式来看待这个问题:编译器以这种方式运行因为这是指定语言的方式

来自 ECMA C# 5 规范第 10.4.4.16 节:

Try-catch-finally statements

Definite assignment analysis for a try-catch-finally statement of the form:

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

is done as if the statement were a try-finally statement enclosing a try-catch statement:

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

那么 try-finally 语句在明确赋值方面是如何工作的呢?这在第 10.4.4.16 节中:

For a try statement stmt of the form:

try try-block finally finally-block

  • ...
  • The definite assignment state of v at the beginning of finally-block is the same as the definite assignment state of v at the beginning of stmt.

那么这对你来说意味着什么?在语句的开头,您的变量 str 并未明确分配...因此根据这些规则,它finally 的开头也未明确分配 block 。

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

作为一个简单的示例,假设我们将您的代码更改为:

string str;
try
{
    str = MethodThatThrowsAnException();
}
catch (Exception)
{
    str = MethodThatThrowsAnException();
}
finally
{
    Console.WriteLine(str);
}

此时,str 未明确分配似乎并不奇怪。只是因为它分配了一个字符串文字,所以看起来不可能失败。但我可以想象,如果这是第一次看到该字符串常量,并且它需要分配一个 String 对象,那么即使分配一个字符串文字也会失败……分配可能会失败。然后还有所有其他可能引发异常的方式,包括中止线程。

所有这些意味着:

  • try block 中的第一个语句可以引发异常
  • catch block 中的第一个语句可以引发异常

在这种情况下 - 无论发生什么情况,也无论它是否与线程有关(例如,可能是分配失败) - 您将不会执行对 str 的任何赋值>,因此它没有定义的值可供读取。

关于C# 局部变量在 Try-Catch-Finally 中访问之前可能不会初始化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50882359/

相关文章:

c++ - Set表现异常:本地还是非本地?

ruby - 我想在这里使用什么样的 Ruby 变量?

c# - EPPlus 不支持 ExcelHorizo​​ntalAlignment Center 或 Right

c# - UserControl 中的依赖属性绑定(bind)

c# - 在 C# 中使用 'unnecessary' 局部变量的性能损失?

java - 如何让try-finally中的finally等待线程完成?

javascript - 我可以在 Node.js 的 javascript 中使用 catch(e if e instanceof SyntaxError) 吗?

c# - 将 C# TripleDESCryptoServiceProvider 加密移植到 PHP

c# - 使用 .net c# 在 Windows 窗体应用程序中验证印度电话号码?

java - 为什么我们不应该在 catch block 中进行清理?