编译器/JIT能否将嵌套的using合并到单个try/catch块中



编译器是否能够将以下任何代码合并到单个try/catch中?

using (FileStream stream = new FileStream(filePath, FileMode.Open))
{
    using (BinaryReader reader = new BinaryReader(stream))
    {
        a try/catch around my actual code...
    }
}

如果没有,如果我改为这样做,会有什么功能上的区别吗?

FileStream stream = null;
BinaryReader reader = null;
try
{
    stream = new FileStream(filePath, FileMode.Open);
    reader = new BinaryReader(stream)
    // do my stuff
}
catch (stuff)
{
}
finally
{
    if (stream != null)
        stream.Close();
    if (reader != null)
        reader.Close();
}

由于拥有一个额外的try/finally的开销实际上为零,因此编译器将两个块合并为一个或将它们分开是没有区别的。翻译后的代码将在try-finally的两层中嵌入一个try-catch,这两层在性能方面几乎是免费的。

手动转换using代码有不同的含义——变量的可见性不同。嵌套using语句的转换使streamreader变量在块之后可以访问。它们指的是封闭的流和封闭的读者。另一方面,正则using将其变量保持在的范围内,就好像在整个块周围放置了一对额外的花括号:

{   // <<==
    FileStream stream = null;
    BinaryReader reader = null;
    try {
        stream = new FileStream(filePath, FileMode.Open);
        reader = new BinaryReader(stream)
        // do my stuff
    } finally {
        if (stream != null)
            stream.Close();
        if (reader != null)
            reader.Close();
    }
}   // <<==

using在这种方式下更好,因为它可以避免额外级别的嵌套,同时将其变量保持在本地范围内。此外,您可以通过将两个连续的using块放在同一缩进级别,不使用大括号来降低源代码中的嵌套级别:

using (FileStream stream = new FileStream(filePath, FileMode.Open))
using (BinaryReader reader = new BinaryReader(stream)) {
    a try/catch around my actual code...
}

编译器是否能够将以下任何代码合并为一个try/catch?

不,编译器无法使代码的行为与您编写的代码不同。即使没有Close()Dispose()产生不同影响的可能性,情况也会有所不同,但让我们假设你自己打过Dispose()

如果没有,如果我改为这样做,会有什么功能上的区别吗?

是的。将两个Dispose()调用放在一个finally块中意味着,如果stream.Dispose()抛出异常,则不会释放reader

没有编写良好的IDisposableDispose()方法抛出异常,但编译器不能知道或假设所有实现都编写良好。

最新更新