首页 > 解决方案 > 在 try 块中返回的伪代码是什么?

问题描述

以下代码

class Animal : IDisposable
{
    static string Invoker()
    {
        using (Animal a = new Animal())
        {
            return a.Greeting();
        }
    }

    public void Dispose()
    {
        Console.WriteLine("Disposed");
    }

    public string Greeting()
    {
        return "Hello World";
    }

    static void Main()
    {
        Console.WriteLine("Before");
        Console.WriteLine(Invoker());
        Console.WriteLine("After");
    }
}

生产

Before
Disposed
Hello World
After

因为这个输出在Disposed之前Hello World,我猜

using (Animal a = new Animal())
{
    return a.Greeting();
}

相当于

Animal a = new Animal();
string buffer = null;
try
{
    buffer = a.Greeting();
}
finally
{
    a.Dispose();
    return buffer;
}

但是,这显然是不正确的,因为以下错误消息:

控制不能离开 finally 块的主体。

那么我的最终猜测就变成了如下。

Animal a = new Animal();
string buffer = null;
try
{
    buffer = a.Greeting();
    return buffer;
}
finally
{
    a.Dispose();
    //return buffer;
}

但是,我仍然很困惑Dispose()如果return buffer在执行顺序中首先调用,如何调用。尽早离开函数体使得Dispose()必须由某些东西(其他代理或线程或垃圾收集器或我不详细了解的任何隐藏机制)调用。这是我的想象。另外,如果return buffer先出现,那么输出应该是

Before
Hello World
Disposed
After

问题

你能告诉我编译器或内部机制是如何调用的Dispose(),而return buffer先到先得导致过早地离开函数体Invoker吗?

标签: c#

解决方案


语言规范说这种形式的 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, orreturn语句的结果,还是从语句中传播异常的结果,都是如此try


推荐阅读