为什么在 try 和 catch 部分都需要初始化 out 参数?
Why out parameters are required to be initialized inside both try and catch sections?
我注意到 C# 编译器 (.NET 4.5.2) 不允许我编译以下代码:
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
也阻止?
原因是因为out
关键字保证参数在方法退出前被赋值。因此,如果在 value = null;
行执行之前引发异常,并且 catch 块中没有对该参数的赋值,则该保证被打破。
如果您有一个 if else
语句,其中两个逻辑块之一未执行赋值,则结果相同。
正如 the MSDN 所指出的,out
和 ref
的相似之处在于对该参数所做的赋值将自行带出方法,但 ref
不会做出同样的保证。因此,如果所需的结果是 try catch
,其中 catch
块中没有赋值,那么也许您需要 ref
关键字。
另外,如果这个赋值是 try
块中的最后一行执行,你可以在逻辑上将它移到 finally
块中,这保证它会在异常发生时执行扔在 try
中,因此满足 out
.
的要求
您必须在函数体中设置输出参数。因为 try 块中的代码可能会或可能不会执行(因为可能会抛出错误并且控制可能会转移到错误处理程序),所以您必须在离开函数之前在某处设置变量。在catch
块是有效的地方,在before/after是try { ... } catch{ ... }
,或者在finally { ... }
块是
根据 C# Sepcification,
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
的情况下,函数可以 return 来自 Try 或来自 catch。所以有两个执行路径,因此根据规范编译器会在编译时检查 output parameters
是否在两个执行路径中都分配了一个值。
您的问题的解决方案是为 out parameter
分配一个默认值。稍后您可以在 Try
中使用适当的值对其进行初始化,编译器不会打扰您。
编译器没有足够的智慧来理解 try 块中的代码可能有多个部分,不会失败的部分和 可能 失败的部分。
您已经在 try 块中初始化了 out
参数这一事实对于编译器来说已经足够了,try 块中的任何事情都可能根本不会发生,因此 out
参数 可能 在方法 returns 之前没有被赋值,因此你会得到错误。
当您将初始化添加到 catch 块时,您基本上是在说(根据编译器可以理解的内容)我理解 try 块中的代码可能没有完全执行或根本没有执行,所以请确保在继续之前完成此操作。
我注意到 C# 编译器 (.NET 4.5.2) 不允许我编译以下代码:
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
也阻止?
原因是因为out
关键字保证参数在方法退出前被赋值。因此,如果在 value = null;
行执行之前引发异常,并且 catch 块中没有对该参数的赋值,则该保证被打破。
如果您有一个 if else
语句,其中两个逻辑块之一未执行赋值,则结果相同。
正如 the MSDN 所指出的,out
和 ref
的相似之处在于对该参数所做的赋值将自行带出方法,但 ref
不会做出同样的保证。因此,如果所需的结果是 try catch
,其中 catch
块中没有赋值,那么也许您需要 ref
关键字。
另外,如果这个赋值是 try
块中的最后一行执行,你可以在逻辑上将它移到 finally
块中,这保证它会在异常发生时执行扔在 try
中,因此满足 out
.
您必须在函数体中设置输出参数。因为 try 块中的代码可能会或可能不会执行(因为可能会抛出错误并且控制可能会转移到错误处理程序),所以您必须在离开函数之前在某处设置变量。在catch
块是有效的地方,在before/after是try { ... } catch{ ... }
,或者在finally { ... }
块是
根据 C# Sepcification,
All output parameters of a function member must be definitely assigned at each location where the
function member returns
(through areturn statement
orthrough 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
的情况下,函数可以 return 来自 Try 或来自 catch。所以有两个执行路径,因此根据规范编译器会在编译时检查 output parameters
是否在两个执行路径中都分配了一个值。
您的问题的解决方案是为 out parameter
分配一个默认值。稍后您可以在 Try
中使用适当的值对其进行初始化,编译器不会打扰您。
编译器没有足够的智慧来理解 try 块中的代码可能有多个部分,不会失败的部分和 可能 失败的部分。
您已经在 try 块中初始化了 out
参数这一事实对于编译器来说已经足够了,try 块中的任何事情都可能根本不会发生,因此 out
参数 可能 在方法 returns 之前没有被赋值,因此你会得到错误。
当您将初始化添加到 catch 块时,您基本上是在说(根据编译器可以理解的内容)我理解 try 块中的代码可能没有完全执行或根本没有执行,所以请确保在继续之前完成此操作。