C# 'using' 语句被编译器翻译为 'try finally'

Jam*_*ing 2 c#

根据MSDN这个接受的答案

using (T resource = expression)
    embedded-statement
Run Code Online (Sandbox Code Playgroud)

被编译器翻译为以下代码:

{
    T resource = expression;//Shouldn't this statement be moved inside the try block?
    try
    {
        embedded-statement
    }
    finally
    {
        if (resource != null)
             ((IDisposable)resource).Dispose();
    }
}
Run Code Online (Sandbox Code Playgroud)

{}我的问题是:为什么try 块周围有多余的东西?第一个语句不应该移到 try 块内吗?

MSDN解释道:

前面的代码示例在编译时扩展为以下代码 (请注意额外的花括号来创建对象的有限范围)

但根据另一个MSDN页面,

通过使用finally块,您可以清理try块中分配的所有资源

更新:如果变量可见性是原因,那么我们首先声明变量并将其分配为 null,然后在 try 块内初始化它怎么样?这比原来的代码好吗?

{
    T resource = null;//Now it is visible in the try block
    try
    {
        resource =expression;// in case an exception is thrown here
        embedded-statement
    }
    finally
    {
        if (resource != null)
             ((IDisposable)resource).Dispose();
    }
}
Run Code Online (Sandbox Code Playgroud)

Swe*_*per 8

{}为什么try 块周围有多余的东西?

因为该using语句不等于:

T resource = expression;
try
{
    embedded-statement
}
finally
{
    if (resource != null)
         ((IDisposable)resource).Dispose();
}

// resource is still in scope here!
Run Code Online (Sandbox Code Playgroud)

resource在上面的代码之后仍然在范围内,但它不应该在using语句之后的范围内。

想象一下 ifresource也是一个字段的名称,并且您将其放在语句Console.WriteLine(resource);后面using。通常,它会打印该字段,但如果该using语句被上面的代码替换,那么您将打印刚刚分配的资源!

因此,为了确保语义保持不变,{}需要额外的。

第一个语句不应该移到 try 块内吗?

不会。该using语句旨在在资源初始化失败时引发异常。

通过使用finally块,您可以清理try块中分配的所有资源

是的,但这并不意味着您必须将所有资源放入一个try块中,也不意味着将资源放入一个try块中是清理它们的唯一方法。

如果 的初始化resource抛出异常,则资源将不会被初始化,因此无论如何都没有要处置的资源 -finally在这种情况下该块不需要运行,因此将该行放在try.