【问题标题】:Best practice for nested using statements?嵌套 using 语句的最佳实践?
【发布时间】:2014-06-05 12:43:18
【问题描述】:

我有一个如下代码块,我正在使用 3 个嵌套的 using 块。

我发现使用 try finally 块可以避免这种情况,但如果有两个以上 using 语句,最好的方法是什么?

private FileStream fileStream = null;
private Document document = null;
private PdfWriter pdfWriter =  null;

using (fileStream = new FileStream("ABC.pdf", FileMode.Create))
{
    using (document = new Document(PageSize.A4, marginLeft, marginRight, marginTop, marginBottom))
    {
        using (pdfWriter = PdfWriter.GetInstance(document, fileStream))
        {
            document.AddAuthor(metaInformation["author"]);
            document.AddCreator(metaInformation["creator"]);
            document.AddKeywords("Report Generation using I Text");
            document.AddSubject("Document subject");
            document.AddTitle("The document title");
        }
    }
}

【问题讨论】:

  • 我认为这没有问题。
  • 每个 using 语句都将转换为 try-finally 块。所以这真的取决于你打算如何用try-finally 替换你当前的结构。每个 using 块一个 try/finally 或多个 try/finally
  • 你真的需要这些作为实例变量吗?在using 语句之后,它们无论如何都会被处置(因此可能无用) - 你可以将它们改为局部变量,在using 语句中声明吗?
  • 使用new 实例化可能会失败,但会引发异常。使用 Class.GetInstance() 静态方法进行实例化可能会失败但返回 null。无论哪种情况,代码都应该检查并恢复。
  • Yap @ClickRick 我会重构它,谢谢

标签: c# .net using-statement


【解决方案1】:

现在在 C# 8 上你有 using declarations

    using var fileStream = new FileStream("ABC.pdf", FileMode.Create);
    using var document = new Document(PageSize.A4, marginLeft, marginRight, marginTop, marginBottom);
    using var pdfWriter = PdfWriter.GetInstance(this.document, this.fileStream);

【讨论】:

    【解决方案2】:

    你可以这样去掉缩进和大括号:

    using (var fileStream = new FileStream("ABC.pdf", FileMode.Create))
    using (var document = new Document(PageSize.A4, marginLeft, marginRight, marginTop, marginBottom))
    using (var pdfWriter = PdfWriter.GetInstance(document, fileStream))
    {
       // code
    }
    

    【讨论】:

      【解决方案3】:

      在不需要处理或更改数据的单一方法中; Jan Sommer 建议的选项是我的选择。但是,在某些情况下 DisposableList 很有用。特别是,如果您有许多一次性字段都需要处理(在这种情况下您不能使用 using)。

      要求您记住将项目添加到列表中。 (虽然你也可以说你必须记住使用 using。) 如果其中一个 disposes 方法抛出,则中止处置过程,使剩余的项目未处置。

      public class DisposableList : List<IDisposable>, IDisposable
      {
          public void Dispose()
          {
              if (this.Count > 0)
              {
                  List<Exception> exceptions = new List<Exception>();
      
                  foreach (var disposable in this)
                  {
                      try
                      {
                          disposable.Dispose();
                      }
                      catch (Exception e)
                      {
                          exceptions.Add(e);
                      }
                  }
                  base.Clear();
      
                  if (exceptions.Count > 0)
                      throw new AggregateException(exceptions);
              }
          }
      
          public T Add<T>(Func<T> factory) where T : IDisposable
          {
              var item = factory();
              base.Add(item);
              return item;
          }
      }
      

      现在从 Dispose 调用中捕获任何异常,并在遍历所有项目后抛出新的 AggregateException。我添加了一个助手 Add 方法,它允许更简单的使用:

      using (var disposables = new DisposableList())
      {
              var file = disposables.Add(() => File.Create("test"));
              // ...
              var memory = disposables.Add(() => new MemoryStream());
              // ...
              var cts = disposables.Add(() => new CancellationTokenSource());
              // ... 
      }
      

      【讨论】:

        【解决方案4】:

        也许是传统的在我看来在两个之间进行选择的最佳方法是;

        • Using :如果您要在上下文中使用实例,并且在完成后需要 Dispose
        • try/finally :如果您预计有任何问题并且与异常有关,请在 Dispose 您正在使用的实例之前捕获它。

        正如其他 cmets / answers 状态;你不需要 instance 级别的变量;

        using (FileStream fileStream = new FileStream("ABC.pdf", FileMode.Create))
        using (Document document = new Document(PageSize.A4, marginLeft, marginRight, marginTop, marginBottom))
        using (PdfWriter pdfWriter = PdfWriter.GetInstance(document, fileStream))
        {
            // # Implementation here seems like a good approach
        }
        

        【讨论】:

          【解决方案5】:

          避免缩进的更简洁的方法:

            using (var fileStream = new FileStream("ABC.pdf", FileMode.Create))
            using (var document = new Document(PageSize.A4, marginLeft, marginRight, marginTop, marginBottom))
            using (var pdfWriter = PdfWriter.GetInstance(document, fileStream))
            {
                 document.AddAuthor(metaInformation["author"]);
                 document.AddCreator(metaInformation["creator"]);
                 document.AddKeywords("Report Generation using I Text");
                 document.AddSubject("Document subject - Describing the steps creating a PDF document");
                 document.AddTitle("The document title - PDF creation using iTextSharp");
             }
          

          正如 Jon Skeet 所指出的,这些变量不需要是实例变量,因为它们无论如何都在 using 块之后被处理。

          您可以改用上面代码中所示的局部变量。

          【讨论】:

            猜你喜欢
            • 2011-03-21
            • 1970-01-01
            • 1970-01-01
            • 2013-10-02
            • 2011-07-12
            • 1970-01-01
            • 2019-03-16
            • 1970-01-01
            相关资源
            最近更新 更多