【问题标题】:Is it necessary to nest usings with IDisposable objects?是否有必要将 usings 与 IDisposable 对象嵌套?
【发布时间】:2012-09-12 02:48:39
【问题描述】:

我是否必须将所有IDisposable 对象包装在using(){} 语句中,即使我只是将一个对象传递给另一个对象?例如,在以下方法中:

public static string ReadResponse(HttpWebResponse response)
{
    string resp = null;
    using (Stream responseStream = response.GetResponseStream())
    {
        using (StreamReader responseReader = new StreamReader(responseStream))
        {
            resp = responseReader.ReadToEnd();
        }
    }
    return resp;
}

我可以像这样将其合并为一个using

public static string ReadResponse(HttpWebResponse response)
{
    string resp = null;
    using (StreamReader reader = new StreamReader(response.GetResponseStream()))
    {
        resp = reader.ReadToEnd();
    }
    return resp;
}

我可以指望StreamStreamReader 都被处置吗?还是我必须使用两个using 语句?

【问题讨论】:

    标签: c#


    【解决方案1】:

    是的,你可以,但那是因为 StreamReader 构造函数文档明确指出:“当 StreamReader.Dispose 被调用时,StreamReader 对象在提供的 Stream 对象上调用 Dispose。 "

    如果没有,那么你可以做这样的事情至少清理一下代码。

    using (Stream responseStream = response.GetResponseStream())
    using (StreamReader responseReader = new StreamReader(responseStream))
    {
        resp = responseReader.ReadToEnd();
    }
    

    【讨论】:

    • 我喜欢堆叠使用,比大量压痕干净得多:-)
    • 认为大括号是可选的。它们与任何其他语句(例如“if”语句)的方式相同。编写“if (expression) if (expression2) if (expression3) { /* 多行代码。*/ }” 是有效的代码,其中每个 if 语句嵌套在前一个中。
    • @Moozhe 它编译并不奇怪,更重要的是VS如何处理缩进。当您使用括号时,它会在一个额外的级别中添加标签,而当您这样做时,它不会。如果这样做在一个关卡中将其设置为选项卡,我可能什至不会使用它。
    【解决方案2】:

    创建一次性对象的人/代码/层通常应该负责处理对象。但是,您可能会遇到一些情况并非如此,但这没关系。这成为文档的问题。

    【讨论】:

      【解决方案3】:

      我发现这个问题比using 语句嵌套的简单问题更广泛,这是一个非常有趣的应用程序设计问题。

      我是否必须将所有 IDisposable 对象包装在 using(){} 语句中, 即使我只是将一个传给另一个?

      是的,因为您正在实例化实现 IDisposable 的对象 - 您知道通过包装 using() 或显式 Dispose() 调用来处理它。

      这背后的原因很简单,想象下一个场景:你有以下实体

      • 运输服务
      • 报告服务
      • FeedService

      所有实现IDisposableReportServiceFeedService 都需要在构造阶段传入 TransportService 的实例。还有问题 - 在 ReportService 或 FeedService 的 Dispose() 中配置 TransportService 是否正确?不!因为可以在两个服务中传递相同的传输服务实例,并且一旦其中一个处理传输 - 这也会影响所有服务。

      public sealed class ReportService : IDisposable
      {       
         private readonly ITransportService transportService;
      
         public ReportService(ITransportService transportService)
         {
             this.transportService = transportService;
         }
      
         public Dispose()
         {
            // ReportService should not dispose objects
            // passed in since they could be used by other classes as well
            // DO NOT: transportService.Dispose();
         }
      }
      

      【讨论】:

      • 这不是一个真正的“总是丢弃”或“从不丢弃”的问题。有两条路;当您将一次性物品传递给另一个您不再负责处置它的物品时,无论他们将其传递给什么,都将确保它被处置。这就是这里发生的事情。当您将流传递给流式阅读器时,您是在说“您处理这个流”。如果您将一次性对象提供给其他人,但说“我仍然负责处理这个,它的范围比你的大”,那么您传递给它的对象甚至不需要实现 IDisposable。
      • 您会看到很多使用 DataContexts 的后者示例。我可能有一个辅助方法/类,它接受一个 DataContext 的实例,甚至不是一次性的。它不会处理 DataContext,它知道无论谁将 DataContext 交给它,都会负责清理它并确保在我仍在使用它时不会处理它。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-02
      • 1970-01-01
      • 2020-01-31
      • 2021-11-19
      • 2016-09-29
      • 2014-08-22
      相关资源
      最近更新 更多