2015-09-04 49 views
4

我注意到,C#编译器(.NET 4.5.2)不允许我编译下面的代码:为什么out参数需要在try和catch部分内初始化?

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

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

它失败,出现以下错误:

The out parameter 'value' must be assigned to before control leaves the current method

但如果我正在取消catch部分中的作业,它编译成功。
很明显,它也编译我在try声明之前取消注释。

所以问题是为什么它不足以在try块中初始化参数out为什么我不得不在catch模块中进行初始化?

+0

此代码永远不会失败,但编译器在编译时不检查它。 –

+1

@ M.kazemAkhgary:你怎么知道它永远不会失败?在'null'可以存储在变量中之前,必须用'ldnull'将它压入堆栈。没有理由不能导致'StackOverflowException'或其他什么。 –

+0

@DarkFalcon请添加作为答案 - 所有其他答案只是引用语言规范。我正在寻找一个真正的原因,但想不出一个。 – xxbbcc

回答

1

编译器没有足够的智能来理解try-block中的代码可能包含多个部分,不会失败的部分以及可能会失败的部分。

你已经初始化的试块内out参数事实是根本不够的编译器,在try块里的任何东西可能根本不会发生,因此out参数可能尚未给予该方法返回之前的值,因此您会得到该错误。

当您将初始化添加到catch-block时,您基本上会说(根据编译器的理解),我明白try-block中的代码可能没有完全执行或完全执行,所以请确保在继续之前完成此操作。

+1

不,编译器*确实*有足够的智能知道try块*可以*在任何时候失败,甚至在它可以分配之前。假设try块*必须分配值,这将是* invalid *。 – Servy

6

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

如果您有一个if else语句,其中两个逻辑块之一没有执行任务,那么它们应该是相同的。

正如注意到the MSDNoutref很相似,分配到该参数将开展自己的方法的制造,但ref不作此相同的保证。因此,如果期望的结果是try catch,其中catch块中没有分配,则可能需要ref关键字。

此外,如果这个任务是要在try块执行的最后一行,你可以在逻辑上它移动到finally块,这保证了一个异常的try抛出,因此它会执行,满足out的要求。

+0

起初,我想写一些类似的东西,但是'if..else'与初始化变量明显不同,就像'try'中的第一个实际语句。如果'try'没有执行,甚至不能保证'catch'将会执行。 – xxbbcc

+0

@xxbbcc在这种情况下程序将停止工作!所以没有更多的步骤 –

+0

@ M.kazemAkhgary是的。这不会阻止编译器了解该变量已在'try'块中初始化。 – xxbbcc

3

必须在函数体中设置out参数。由于try块中的代码可能执行也可能不执行(因为可能会抛出错误并将控制权移交给错误处理程序),所以在离开函数之前,必须在某处设置变量。在catch块是一个有效的地方,是前/ try { ... } catch{ ... }后,或在finally { ... }

3

根据C#规格说明,它说

All output parameters of a function member must be definitely assigned at each location where the function member returns (through a return statement or through execution reaching the end of the function member body). This ensures that function members do not return undefined values in output parameters, thus enabling the compiler to consider a function member invocation that takes a variable as an output parameter equivalent to an assignment to the variable.

try..catch情况下,函数既可以从返回尝试或从赶上。因此,如果output parameters已在两个执行路径中分配了一个值,则每个规范编译器都会编译时间检查,因此有两个执行路径。

解决您的问题的方法是将默认值分配给out parameter。稍后,您可以用适当的值在Try中初始化它,编译器不会打扰您。