在设置out参数的值之前抛出异常时,C#中定义的行为是什么,然后尝试访问参数?
public void DoSomething(int id, out control)
{
try
{
int results = Call(Id);
control = new CallControl(results);
}
catch(Exception e)
{
throw new Exception("Call failed", e);
}
}
//somewhere else
DoSomething(out Control control)
{
try
{
DoSomething(1, out control);
}
catch()
{
// handle exception
}
}
// later
Control control;
DoSomething(out control)
control.Show();
编译器通常会在设置out参数之前抱怨退出该方法。这似乎超越了保护我自己。
答案 0 :(得分:4)
在设置out参数的值之前抛出异常时,C#中定义的行为是什么,然后尝试访问参数?
你不能这样做。除非在方法调用之前明确赋值,否则变量仍然不会被明确赋值。
如果在方法调用之前明确赋值变量 ,那么它仍然会被明确分配 - 但除非方法在之前分配了值,否则抛出异常,变量的值将保持不变:
class Test
{
static void JustThrow(out int x)
{
throw new Exception();
}
static void Main()
{
int y = 10;
try
{
JustThrow(out y);
}
catch
{
// Ignore
}
Console.WriteLine(y); // Still prints 10
}
}
答案 1 :(得分:1)
没关系。如果DoSomething
抛出,则control.Show()
未执行。
答案 2 :(得分:0)
无论如何,你无法超越编译器,因为它知道控制流何时可以绕过初始化。
考虑这段代码,它类似于你提出的代码:
using System;
namespace Demo
{
internal class Program
{
private void run()
{
int a;
try
{
DoSomething(out a);
}
catch {} // Evil empty catch.
Console.WriteLine(a); // Compile error.
}
public void DoSomething(out int x)
{
test();
x = 0;
}
private static void test()
{
throw new InvalidOperationException("X");
}
private static void Main()
{
new Program().run();
}
}
}
它给出了编译错误,因为你在DoSomething()
附近放了一个try / catch,因此编译器认为a
可能没有被初始化。
(请注意,如果您没有显式初始化它们,所有堆栈变量都会初始化为默认值,但这不会影响编译器的控制流分析。编译器关心明确的赋值,而不是CLR的默认初始化无论如何,C#标准无法保证这种初始化。)
如果将空捕获更改为抛出的捕获,则编译错误消失:
catch { throw new Exception("Test"); } // Compile error goes away.
因为现在如果发生异常,您无法访问使用a
的代码。