【问题标题】:Why out parameters are required to be initialized inside both try and catch sections?为什么在 try 和 catch 部分都需要初始化 out 参数?
【发布时间】:2015-09-04 18:46:00
【问题描述】:

我注意到 C# 编译器 (.NET 4.5.2) 不允许我编译以下代码:

public void Test(out string value)
{
    //value = null;

    try
    {
        value = null;
    }
    catch (Exception ex)
    {
        //value = null;
    }
}

它失败并出现以下错误:

out 参数 'value' 必须在控制离开之前分配给 当前方法

但如果我取消注释 catch 部分中的分配,它编译成功。
显然,当我在 try 语句之前取消注释赋值时,它也会编译。

所以问题是为什么在 try 块中初始化 out 参数是不够的? 为什么我还要在 catch 块中进行初始化?

【问题讨论】:

  • 这段代码永远不会失败,但编译器不会在编译时检查它。
  • @M.kazemAkhgary:你怎么知道它永远不会失败?在将null 存储在变量中之前,必须使用ldnull 将其压入堆栈。没有理由不能导致StackOverflowException 或其他东西。
  • @DarkFalcon 请添加它作为答案 - 所有其他答案都只是引用语言规范。我一直在寻找一个真正的原因,但想不出一个。

标签: c# .net compiler-errors out


【解决方案1】:

原因是因为out关键字保证参数会在方法退出之前被赋值。因此,如果在 value = null; 行执行之前引发了异常,并且在 catch 块中没有分配给该参数,则该保证被打破。

如果您有一个 if else 语句,其中两个逻辑块之一没有执行赋值,If 将是相同的。

正如the MSDN 所指出的,outref 的相似之处在于,对该参数的赋值将使其自身脱离方法,但ref 不做同样的保证。因此,如果所需的结果是 try catch,而 catch 块中没有赋值,那么您可能需要 ref 关键字。

另外,如果这个赋值是在try块中执行的最后一行,你可以在逻辑上把它移到finally块中,这样可以保证在try中抛出异常时它会执行因此,满足out 的要求。

【讨论】:

  • 起初我想写一些类似的东西,但if..else 与将变量初始化为try 中的第一个实际语句明显不同。如果try 不执行,甚至不能保证catch 会执行。
  • @xxbbcc 该案例程序将停止工作!所以没有更多的步骤
  • @M.kazemAkhgary 是的。这不会阻止编译器理解变量已经在 try 块中初始化。
  • @M.kazemAkhgary 如果您的其他评论(在问题下)是有效的,这只是缺少优化和语言要求的情况。我想知道是否有技术原因需要在catch 中进行初始化。
【解决方案2】:

必须在函数体中设置 out 参数。因为 try 块中的代码可能会或可能不会执行(因为可能会引发错误并且控制权可能会转移到错误处理程序),因此您必须在离开函数之前在某处设置变量。在catch 块中是一个有效的位置,就像在try { ... } catch{ ... } 之前/之后,或者在finally { ... } 块中一样

【讨论】:

    【解决方案3】:

    根据 C# Sepcification,它说

    函数成员的所有输出参数必须明确分配在function member returns 所在的每个位置(通过return statementthrough execution reaching the end of the function member body)。这确保了函数成员不会在输出参数中返回未定义的值,从而使编译器能够考虑将变量作为输出参数的函数成员调用等效于对变量的赋值。

    try..catch 的情况下,该函数可以从 Try 或从 catch 返回。所以有两个执行路径,因此根据规范编译器会在编译时检查output parameters 是否在两个执行路径中都分配了一个值。

    解决您的问题的方法是为out parameter 分配一个默认值。稍后您可以在 Try 中使用适当的值对其进行初始化,编译器不会打扰您。

    【讨论】:

      【解决方案4】:

      编译器没有足够的智慧来理解 try 块中的代码可能有多个部分,不会失败的部分和可能失败的部分。

      您已经在 try 块中初始化了 out 参数这一事实对于编译器来说已经足够了,try 块中的任何事情都可能根本不会发生,因此 out 参数可能 /em> 在方法返回之前没有被赋予一个值,因此你得到了错误。

      当您将初始化添加到 catch 块时,您基本上是在说(就编译器可以理解的而言)我理解 try 块中的代码可能没有完全执行或根本没有执行,所以请确保这是在您继续之前完成的。

      【讨论】:

      • 不,编译器 确实 有足够的智慧知道 try 块 可以 在任何时候失败,甚至在赋值之前,它可以.假设 try 块 必须 分配值是无效
      猜你喜欢
      • 2014-12-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-01-18
      • 1970-01-01
      • 2014-11-07
      • 1970-01-01
      相关资源
      最近更新 更多