输出参数和异常
说我有下面的代码:“fjuk”输出参数和异常
static void Fjuk(out string str)
{
str = "fjuk!";
throw new Exception();
}
static void Main(string[] args)
{
string s = null;
try
{
Fjuk(out s);
}
catch (Exception)
{
Console.WriteLine(s ?? "");
}
}
当我测试了一下,s
已经被初始化到当它在catch
区块中使用时。
这是由规范保证还是依赖于实现? (我已经搜查了C#3.0规范,但无法找到自己)
差不多,即什么out
手段一个方面;首先,请注意out
并不存在 - 我们只需要考虑ref
(out
仅仅是ref
,在编译器中有一些“明确的分配”调整)。 ref
的意思是“传递这个地址” - 如果我们通过地址更改值,那么立即显示 - 它毕竟是更新内存的堆栈Main
。它不能抽象这个(延迟写入),因为这个值可能是,例如,一些特别用于避免将其复制到堆栈上的超大结构(在XNA等中广泛使用的一种方法)。
如果该方法抛出异常,则不保证输出参数被设置。如果该方法没有异常退出,则保证输出参数被设置。
在你的情况下,该方法将始终设置输出参数,但编译器不会以这种方式分析该方法的代码。如果该方法退出并出现异常,则输出参数仍然不被认为是明确设置的。
您在异常处理程序中的代码不依赖于由方法调用设置的变量,因为您在创建变量时设置该变量。如果您在创建时没有设置变量,异常处理程序不能使用它,因为它不能保证设置:
string s;
try {
Fjuk(out s);
Console.WriteLine(s); // here the variable is guaranteed to be set
} catch (Exception) {
Console.WriteLine(s); // here it's not, so this won't compile
}
是的,我认为它很明显,它不检查被调用方法中的代码,但没有在我的例子中说清楚。感谢您指出了这一点! – Niklas 2012-01-18 11:36:39
它从Fjuk
角度保证,但不是Main
。
在Fjuk
设置参数后抛出异常。尽管可以通过编译器,抖动和CPU完成重新排序,但不会有重新排序,以致单个线程观察到的顺序发生变化。由于单个线程可能会“注意到”在抛出异常之前未设置参数,因此参数将保证设置。
尽管在Main
中,我们并不知道Fjuk
的实现细节,所以当编译器分析Main
时,它不能依赖于此。因此,在变化,我们不调用之前的值赋给s
:
static void Main()
{
string s;
try
{
Fjuk(out s);
Console.WriteLine(s ?? "");//fine
}
catch (Exception)
{
Console.WriteLine(s ?? "");//compiler error
}
Console.WriteLine(s ?? "");//compiler error
}
使用s
后马上打电话给Fjuk
是好的,因为一次只能到达那里,如果Fjuk
成功的第一次尝试,如果Fjuk
成功,则必须分配s
。然而,在第二和第三种情况下,可以在没有Fjuk
成功的情况下到达那些行,并且由于无法通过分析Main
分析是否可以在设置s
之前抛出异常,因此必须禁止使用s
。
我不知道规范,但它肯定是我期望的。我期望成员变量,属性等的初始化也将在你的catch块中可用。 – 2012-01-18 07:57:30
Eric Lippert在什么时候需要他...... :) – 2012-01-18 08:00:52
@jb。 [MSDN]有什么问题(http://msdn.microsoft.com/en-us/library/t3c3bfhx(v = vs.80).aspx)? – gdoron 2012-01-18 08:08:59