我的代码是否正确清理了List <memorystream>?</memorystream>

时间:2009-03-19 01:52:37

标签: c# dispose idisposable memorystream

我有一个执行PDF文件操作的第三方组件。每当我需要执行操作时,我都会从文档存储(数据库,SharePoint,文件系统等)中检索PDF文档。为了使事情稍微一致,我将PDF文档作为byte[]传递。

此第三方组件需要MemoryStream[]MemoryStream数组)作为我需要使用的主要方法之一的参数。

我正在尝试将此功能包装在我自己的组件中,以便我可以将此功能用于我的应用程序中的许多区域。我基本上提出了以下几点:

public class PdfDocumentManipulator : IDisposable
{
   List<MemoryStream> pdfDocumentStreams = new List<MemoryStream>();

   public void AddFileToManipulate(byte[] pdfDocument)
   {
      using (MemoryStream stream = new MemoryStream(pdfDocument))
      {
         pdfDocumentStreams.Add(stream);
      }
   }

   public byte[] ManipulatePdfDocuments()
   {
      byte[] outputBytes = null;

      using (MemoryStream outputStream = new MemoryStream())
      {
           ThirdPartyComponent component = new ThirdPartyComponent();
           component.Manipuate(this.pdfDocumentStreams.ToArray(), outputStream);

           //move to begining
           outputStream.Seek(0, SeekOrigin.Begin);

           //convert the memory stream to a byte array
           outputBytes = outputStream.ToArray();
      }

      return outputBytes;
   }

   #region IDisposable Members
   public void Dispose()
   {
       for (int i = this.pdfDocumentStreams.Count - 1; i >= 0; i--)
       {
          MemoryStream stream = this.pdfDocumentStreams[i];
          this.pdfDocumentStreams.RemoveAt(i);
          stream.Dispose();
       }
   }
   #endregion
}

我的“包装器”的调用代码如下所示:

    byte[] manipulatedResult = null;
    using (PdfDocumentManipulator manipulator = new PdfDocumentManipulator())
    {
        manipulator.AddFileToManipulate(file1bytes);
        manipulator.AddFileToManipulate(file2bytes);
        manipulatedResult = manipulator.Manipulate();
    }

关于上述问题的一些问题:

  1. using方法中的AddFileToManipulate()子句是多余的还是不必要的?
  2. 我在对象的Dispose()方法中清理好了吗?
  3. 这是MemoryStream的“可接受”用法吗?我不是一次在内存中预期很多文件...可能总共1-10页PDF页面,每页大约200KB。应用程序旨在运行在支持ASP.NET站点的服务器上。
  4. 有任何意见/建议吗?
  5. 感谢代码审核:)

4 个答案:

答案 0 :(得分:4)

AddFileToManipulate吓到了我。

   public void AddFileToManipulate(byte[] pdfDocument)
   {
      using (MemoryStream stream = new MemoryStream(pdfDocument))
      {
         pdfDocumentStreams.Add(stream);
      }
   }

此代码正在向pdfDocumentStream列表中添加已处理的流。相反,您应该使用以下方法添加流:

   pdfDocumentStreams.Add(new MemoryStream(pdfDocument));

并在Dispose方法中处理它。

此外,您应该考虑实现终结器,以确保在有人忘记处置顶级对象的情况下处理内容。

答案 1 :(得分:3)

  1. AddFileToManipulate()方法中的using子句是多余的还是不必要的?
  2. 更糟糕的是,它具有破坏性。你基本上是在关闭你的内存流之前关闭你的内存流。有关详细信息,请参阅其他答案,但基本上,最后处理,但不是任何其他时间。每次使用对象都会导致Dispose发生在块的末尾,即使对象通过方法“传递”到其他对象。

    1. 我在对象的Dispose()方法中清理好了吗?
    2. 是的,但是你的生活比现在更困难。试试这个:

      foreach (var stream in this.pdfDocumentStreams)
      {
          stream.Dispose();
      }
      this.pdfDocumentStreams.Clear();
      

      这也很有效,而且更简单。处置对象不会删除它 - 它只是告诉它释放它的内部非托管资源。以这种方式调用对象的处理很好 - 对象在集合中保持未收集状态。您可以执行此操作,然后一次性清除列表。

      1. 这是MemoryStream的“可接受”用法吗?我不是一次在内存中预期很多文件...可能总共1-10页PDF页面,每页大约200KB。应用程序旨在运行在支持ASP.NET站点的服务器上。
      2. 这取决于您的情况。只有你可以确定在内存中使用这些文件的开销是否会导致问题。不过,这将是一个相当重量级的对象,所以我会仔细使用它。

        1. 有任何意见/建议吗?
        2. 实施终结者。无论何时实施IDisposable都是个好主意。此外,您应该将Dispose实现重新设计为标准实现,或将您的类标记为已密封。有关如何执行此操作的详细信息,see this article.特别是,您应该将一个声明为protected virtual void Dispose(bool disposing)的方法设置为Dispose方法和终结器都调用。

答案 2 :(得分:2)

在我看来,你误解了使用的功能。

替换

只是语法糖
MemoryStream ms;
try
{
ms = new MemoryStream();
}
finally
{
ms.Dispose();
}

您在AddFileToManipulate中的使用是多余的。我在PdfDocumentManipulator的构造函数中设置了内存流列表,然后在所有内存流上使用PdfDocumentManipulator的dispose方法调用dispose。

答案 3 :(得分:2)

旁注。这看起来好像需要一个扩展方法。

public static void DisposeAll<T>(this IEnumerable<T> enumerable)
  where T : IDisposable {
  foreach ( var cur in enumerable ) { 
    cur.Dispose();
  }
}

现在您的Dispose方法变为

public void Dispose() { 
  pdfDocumentStreams.Reverse().DisposeAll();
  pdfDocumentStreams.Clear();
}

修改

您不需要3.5框架才能拥有扩展方法。他们将很乐意在3.0编译器上工作,目标是2.0

http://blogs.msdn.com/jaredpar/archive/2007/11/16/extension-methods-without-3-5-framework.aspx