使用语句基础

using 是一个语法糖,可以保证资源被清理而不需要明确的 try-finally 块。这意味着你的代码将更加清晰,并且你不会泄漏非托管资源。

标准的 Dispose 清理模式,用于实现 IDisposable 接口的对象(FileStream 的基类 Stream 在 .NET 中执行):

int Foo()
{
    var fileName = "file.txt";

    {
        FileStream disposable = null;

        try
        {
            disposable = File.Open(fileName, FileMode.Open);

            return disposable.ReadByte();
        }
        finally
        {
            // finally blocks are always run
            if (disposable != null) disposable.Dispose();
        }
    }
}

using 通过隐藏显式 try-finally 简化了语法:

int Foo()
{
    var fileName = "file.txt";

    using (var disposable = File.Open(fileName, FileMode.Open))
    {
        return disposable.ReadByte();
    }
    // disposable.Dispose is called even if we return earlier
}

就像 finally 块总是执行而不管错误或返回,using 总是调用 Dispose(),即使出现错误:

int Foo()
{
    var fileName = "file.txt";

    using (var disposable = File.Open(fileName, FileMode.Open))
    {
        throw new InvalidOperationException();
    }
    // disposable.Dispose is called even if we throw an exception earlier
}

注意: 由于无论代码流如何都保证调用 Dispose,因此确保 Dispose 在实现 IDisposable 时不会抛出异常是个好主意。否则,新异常将覆盖实际异常,从而导致调试噩梦。

从使用块返回

using ( var disposable = new DisposableItem() )
{
    return disposable.SomeProperty;
}

由于 using 块翻译的 try..finally 的语义,return 语句按预期工作 - 在执行 finally 块之前评估返回值并处理该值。评估顺序如下:

  1. 评估 try 的身体
  2. 评估并缓存返回的值
  3. 执行 finally 块
  4. 返回缓存的返回值

但是,你可能不会返回变量 disposable 本身,因为它将包含无效的,已丢弃的引用 - 请参阅相关示例