我注意到C#编译器(.NET 4.5.2)不允许我编译以下代码:
public void Test(out string value)
{
//value = null;
try
{
value = null;
}
catch (Exception ex)
{
//value = null;
}
}
失败并出现以下错误:
out参数'值'必须在控制离开之前分配 目前的方法
但如果我取消注释catch
部分中的作业,则会成功编译。
显然,当我在try
语句之前取消对作业的注释时,它也会编译。
所以问题是为什么它不足以在try块中初始化out
参数?为什么我被强制在{{进行初始化? 1}}阻止?
答案 0 :(得分:6)
原因是out
关键字保证在退出方法之前将参数分配给参数。因此,如果在执行value = null;
行之前引发异常并且在catch块中没有对该参数进行赋值,那么该保证就会被破坏。
如果你有一个if else
语句,其中两个逻辑块中的一个没有执行赋值,那么它们是否相同。
正如the MSDN所述,out
和ref
的相似之处在于,对此参数所做的分配将使自己脱离方法,但ref
不会使同样的保证。因此,如果所需结果为try catch
catch
块中没有分配,那么您可能需要ref
关键字。
此外,如果此赋值是try
块中的最后一行,您可以在逻辑上将其移动到finally
块,这可以保证在发生异常时它将执行try
因此满足out
的要求。
答案 1 :(得分:3)
你必须在你的函数体中设置out参数。因为try块中的代码可能会执行也可能不会执行(因为可能会抛出错误并且控制权可能会转移到错误处理程序中),所以必须在离开函数之前将变量设置为某个位置。在catch
阻止是有效的地方,在try { ... } catch{ ... }
之前/之后,或finally { ... }
阻止
答案 2 :(得分:3)
根据C#Sepcification,其中说
必须在
function member returns
(通过return statement
或through execution reaching the end of the function member body
)的每个位置明确指定函数成员的所有输出参数。这可以确保函数成员不会在输出参数中返回未定义的值,从而使编译器能够考虑一个函数成员调用,该调用将变量作为输出参数,等同于对变量的赋值。
如果try..catch
,该函数可以从Try或from catch返回。因此,有两个执行路径,因此,如果output parameters
在两个执行路径中都分配了值,则规范编译器会进行编译时间检查。
问题的解决方案是为out parameter
分配默认值。稍后您可以使用适当的值在Try
中初始化它,编译器不会打扰您。
答案 3 :(得分:1)
编译器没有足够的智能来理解try-block中的代码可能包含多个部分,不会失败的部分以及可能失败的部分。
您在try-block中初始化out
参数的事实对于编译器来说已经足够了,try-block中的任何内容都可能根本不会发生,因此out
参数< 可能在方法返回之前没有给出值,因此你得到了错误。
当您将初始化添加到catch块时,您基本上是说(就编译器可以理解的内容而言)我理解try-block中的代码可能没有完全执行或者根本没有执行,所以请确保这是在你继续之前完成的。