2 回答
TA贡献1842条经验 获得超21个赞
语言规范 指出这种形式的 using 语句:
using (ResourceType resource = expression) statement
相当于:
{
ResourceType resource = expression;
try {
statement;
}
finally {
((IDisposable)resource).Dispose();
}
}
因此,您的 using 语句相当于:
{
Animal a = new Animal();
try {
return a.Greeting();
} finally {
a.Dispose();
}
}
我只能猜测为什么你认为这是违反直觉的。也许是因为您认为由于 而无法到达 finally
?那么,规范还指定:return
finally
块中的语句总是在控制时执行 留下try
语句。无论控制权转移是否如此 发生作为正常执行的结果,作为执行的结果break
、continue
、goto
或return
语句,或作为以下结果 从try
语句中传播异常。
TA贡献1982条经验 获得超2个赞
该字符串在处理后返回,然后写入控制台。
该字符串在方法结束时返回,即在 dispose 之后返回。
“返回”是指“返回”。函数完成所有操作后返回一个变量。
这就好比一个 goto 是通过所有的finally块到达方法的末尾,然后只在这里返回值。
在您的情况下,您的代码相当于:
static string Invoker()
{
string result;
using (Animal a = new Animal())
{
result = a.Greeting();
goto end;
// a return here is like a "goto end"
// done after invoking the Dispose()
// while exiting the using block
}
// others things possible here
// return anything_else_here;
end:
return result;
}
下面是 VS2017 生成的 IL 代码(使用 .NET Reflector):
.method private hidebysig static string Invoker() cil managed
{
.maxstack 1
.locals init (
[0] class ConsoleApp1.Animal a,
[1] string str)
L_0000: nop
L_0001: newobj instance void ConsoleApp1.Animal::.ctor()
L_0006: stloc.0
L_0007: nop
L_0008: ldloc.0
L_0009: callvirt instance string ConsoleApp1.Animal::Greeting()
L_000e: stloc.1
L_000f: leave.s L_001c
L_0011: ldloc.0
L_0012: brfalse.s L_001b
L_0014: ldloc.0
L_0015: callvirt instance void [mscorlib]System.IDisposable::Dispose()
L_001a: nop
L_001b: endfinally
L_001c: ldloc.1
L_001d: ret
.try L_0007 to L_0011 finally handler L_0011 to L_001c
}
如您所见,ret 位于调用 dispose 之后的末尾。
具体来说,代码将字符串压入堆栈,并在返回到调用方法后将其弹出堆栈以检索字符串。
在此示例中,控制台写入两次内容并等待按键,然后退出该方法:
static string Test()
{
try
{
try
{
return "a string"; // the string is pushed in the stack here
}
finally
{
Console.WriteLine("1");
Console.ReadKey();
// no other return allowed here
}
}
finally
{
Console.WriteLine("2");
Console.ReadKey();
// no other return allowed here
}
}
// The method that calls Test() next pop the stack to retreive the string
这与在该块末尾调用 Dispose 的 using 块发生的情况相同,而要返回的值位于等待调用者弹出的堆栈中。
goto的解释是一个晦涩的解释,如果你了解IL的话你可能会忘记它,但它可以帮助你理解。
- 2 回答
- 0 关注
- 124 浏览
添加回答
举报