代码之家  ›  专栏  ›  技术社区  ›  Brian

我的代码是否正确清除了其列表?

  •  4
  • Brian  · 技术社区  · 17 年前

    我有一个执行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. 这是“可接受”的用法吗 内存流 ?我不希望一次在内存中有太多的文件……可能总共有1-10个PDF页面,每页大约200KB。旨在在支持ASP.NET站点的服务器上运行的应用程序。
    4. 有什么意见/建议吗?

    感谢代码审阅:)

    4 回复  |  直到 17 年前
        1
  •  2
  •   Reed Copsey    17 年前
    1. addFileToManipulate()方法中的using子句是否冗余且不必要?

    更糟的是,它具有破坏性。你基本上是在添加内存流之前关闭它。有关详细信息,请参阅其他答案,但基本上是在最后处理,而不是在任何其他时间。每次对对象使用都会导致在块的末尾发生释放,即使对象通过方法“传递”给其他对象。

    1. 在对象的dispose()方法中,我清理东西是否正常?

    是的,但你让生活变得比需要的更困难。试试这个:

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

    这同样有效,而且更简单。处置一个对象不会删除它-它只是告诉它释放它的内部非托管资源。以这种方式对对象调用Dispose是可以的-对象在集合中保持未收集状态。您可以这样做,然后一次清除列表。

    1. 这是一种“可接受”的memoryStream用法吗?我不希望一次在内存中有太多的文件……可能总共有1-10个PDF页面,每页大约200KB。旨在在支持ASP.NET站点的服务器上运行的应用程序。

    这取决于你的情况。只有您可以确定将这些文件保存在内存中的开销是否会导致您的问题。不过,这将是一个相当重的物体,所以我会小心使用。

    1. 有什么意见/建议吗?

    实现终结器。无论何时实现IDisposable,这都是一个好主意。另外,您应该将Dispose实现返工为标准的实现,或者将类标记为Sealed。有关如何执行此操作的详细信息, see this article. 尤其是,您应该有一个方法声明为 protected virtual void Dispose(bool disposing) 您的Dispose方法和终结器都调用。

        2
  •  4
  •   Sam Saffron James Allen    17 年前

    加上文件来消除恐惧。

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

    此代码正在将已释放的流添加到pdfdocumentstream列表中。相反,您应该使用以下方法简单地添加流:

       pdfDocumentStreams.Add(new MemoryStream(pdfDocument));
    

    并按处置方法处置。

    另外,您还应该考虑实现一个终结器,以确保在有人忘记释放顶级对象的情况下,可以释放一些东西。

        3
  •  2
  •   WOPR    17 年前

    在我看来你误解了使用的作用。

    只是语法上的糖分

    MemoryStream ms;
    try
    {
    ms = new MemoryStream();
    }
    finally
    {
    ms.Dispose();
    }
    

    您在addfiletomanipulate中的使用是多余的。我已经在pdfdocumentManipulator的构造函数中设置了memoryStream的列表,然后对所有memoryStream进行pdfdocumentManipulator的Dispose方法调用Dispose。

        4
  •  2
  •   JaredPar    17 年前

    边注。这似乎真的需要一个扩展方法。

    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