输出参数和异常
假设我有以下代码:
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
已初始化为“fjuk!”当它在 catch
块中使用时。
这是由规范保证的还是依赖于实现? (我搜索了 C# 3 规范,但自己找不到)
Say I have the following code:
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 ?? "");
}
}
When I test it, s
has been initialized to "fjuk!" when it's used in the catch
block.
Is this guaranteed by specification or is it implementation dependent? (I have searched the C# 3 spec but couldn't find out myself)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
几乎,这就是
out
含义的一个方面;首先,请注意out
并不真正存在 - 我们只需要考虑ref
(out
只是ref
> 在编译器上进行一些“明确分配”调整)。ref
表示“传递此地址” - 如果我们通过地址更改值,则显示立即 - 毕竟,它正在更新内存在Main
的堆栈上。它无法抽象这一点(以延迟写入),因为该值可能是一些超大的结构,例如,专门使用ref
来避免将其复制到堆栈上(一种使用的方法)广泛应用于 XNA 等)。Pretty much, that is an aspect of what
out
means; firstly, note thatout
doesn't really exist - we only really need to considerref
(out
is justref
with some "definite assignment" tweaks at the compiler).ref
means "pass the address of this" - if we change the value via the address, then that shows immediately - it is, after all, updating the memory on the stack ofMain
. It can't abstract this (to delay the write) because the value could be, for example, some oversized struct that is usingref
specifically for the purpose of avoiding copying it on the stack (an approach used extensively in XNA etc).这是“有保证的”,因为
out
参数会使用参数的内存地址
更改值。来自 MSDN
It's "guaranteed" because
out
parameter change the value with thememory address
of the parameter.from MSDN
如果该方法引发异常,则不保证设置输出参数。如果该方法无异常退出,则保证设置输出参数。
在您的情况下,该方法将始终设置输出参数,但编译器不会以这种方式分析该方法的代码。如果该方法因异常退出,则输出参数仍然不被视为已明确设置。
异常处理程序中的代码不依赖于方法调用设置的变量,因为您在创建变量时设置该变量。如果在创建变量时未设置该变量,则异常处理程序将无法使用它,因为不能保证已设置该变量:
If the method throws an exception, the output parameter is not guaranteed to be set. If the method exits without an exception, the output parameter is guaranteed to be set.
In your case, the method will always set the output parameter, but the compiler doesn't analyse the code of the method in that way. If the method exits with an exception, the output parameter is still not considered to be definitely set.
Your code in the exception handler doesn't rely on the variable being set by the method call, as you are setting the variable when it's created. If you don't set the variable when it's created, the exception handler can't use it, because it's not guaranteed to be set:
这是从
Fjuk
角度保证的,而不是从Main
角度保证的。在
Fjuk
中,设置参数后会抛出异常。虽然编译器、抖动和 CPU 可以进行重新排序,但不会发生导致单个线程观察到的顺序发生变化的重新排序。由于单个线程可以“注意到”在抛出异常之前是否未设置该参数,因此保证会设置该参数。但在
Main
中,我们不知道Fjuk
的实现细节,因此编译器在分析Main
时,无法依赖关于这一点。因此,在调用之前我们不为s
赋值的变体中:在调用
Fjuk
之后立即尝试使用s
> 很好,因为只有Fjuk
成功才能到达那里,如果Fjuk
成功,则必须分配s
。但在第二种和第三种情况下,有可能在Fjuk
不成功的情况下到达这些行,并且因为无法通过分析Main
来判断是否可以在Fjuk
之前抛出异常。如果设置了 code>s,则必须禁止使用s
。It's guaranteed from the perspective of
Fjuk
but not ofMain
.In
Fjuk
the exception is thrown after the parameter is set. While there can be re-orderings done by compiler, jitter, and CPU, there will not be re-orderings such that the order observed by a single thread changes. Since a single thread could "notice" if the parameter wasn't set before the exception thrown, the parameter is guaranteed to be set.In
Main
though, we have no knowledge of the details ofFjuk
's implementation, so when the compiler analysesMain
, it can't depend on that. Hence in the variation where we don't assign a value tos
before the call:The first attempt to use
s
immediately after the call toFjuk
is fine, because one can only get there ifFjuk
succeeded, and ifFjuk
succeeded thens
must be assigned. In the second and third case though, it's possible to arrive at those lines withoutFjuk
succeeding, and since one cannot tell by analysis ofMain
whether an exception could be thrown befores
is set, the uses ofs
must be prohibited.来自 C# 语言规范第 5.1.6 节输出参数
换句话说,
out
参数总是被分配的。在实践中
From the C# Language Specification section 5.1.6 Output Parameters
In other words
out
parameters are always assigned.In practice