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