Мой код правильно очищает свой список <MemoryStream>? - PullRequest
4 голосов
/ 19 марта 2009

У меня есть сторонний компонент, который выполняет операции с PDF-файлами. Всякий раз, когда мне нужно выполнить операции, я извлекаю документы PDF из хранилища документов (база данных, SharePoint, файловая система и т. Д.). Чтобы все было немного согласованно, я передаю документы в формате 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, каждая страница около 200 КБ. Приложение предназначено для работы на сервере, поддерживающем сайт ASP.NET.
  4. Есть комментарии / предложения?

Спасибо за обзор кода:)

Ответы [ 4 ]

4 голосов
/ 19 марта 2009

AddFileToManipulate пугает меня.

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

Этот код добавляет удаленный поток в список pdfDocumentStream. Вместо этого вы должны просто добавить поток, используя:

   pdfDocumentStreams.Add(new MemoryStream(pdfDocument));

И утилизируйте его в методе Dispose.

Также вам следует взглянуть на реализацию финализатора, чтобы гарантировать, что вещи удаляются в случае, если кто-то забудет избавиться от объекта верхнего уровня.

3 голосов
/ 19 марта 2009
  1. Является ли предложение using в методе AddFileToManipulate () избыточным и ненужным?

Хуже, это разрушительно. Вы в основном закрываете свой поток памяти до того, как он будет добавлен. Подробности смотрите в других ответах, но, в основном, распоряжайтесь в конце, а не в любое другое время. Каждое использование с объектом приводит к тому, что удаление происходит в конце блока, даже если объект «передается» другим объектам с помощью методов.

  1. Очищаю ли я все в порядке в методе Dispose () моего объекта?

Да, но вы делаете жизнь сложнее, чем нужно. Попробуйте это:

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

Это работает так же хорошо, и намного проще. Удаление объекта не удаляет его - он просто сообщает ему освободить его внутренние неуправляемые ресурсы. Вызов метода dispose для объекта в этом случае вполне допустим - объект остается невыбранным в коллекции. Вы можете сделать это, а затем очистить список одним выстрелом.

  1. Является ли это «приемлемым» использованием MemoryStream? Я не ожидаю очень много файлов в памяти одновременно ... Скорее всего, 1-10 всего страниц PDF, каждая страница около 200 КБ. Приложение предназначено для работы на сервере, поддерживающем сайт ASP.NET.

Это зависит от вашей ситуации. Только вы можете определить, будут ли проблемы с размещением этих файлов в памяти причиной ваших проблем. Это будет довольно тяжелый объект, поэтому я буду использовать его осторожно.

  1. Любые комментарии / предложения?

Реализация финализатора. Это хорошая идея, когда вы внедряете IDisposable. Кроме того, вам следует переделать реализацию Dispose в стандартную или пометить класс как закрытый. Подробнее о том, как это сделать, см. в этой статье. В частности, у вас должен быть метод, объявленный как protected virtual void Dispose(bool disposing), который вызовет ваш метод Dispose и ваш финализатор.

2 голосов
/ 19 марта 2009

Примечание. Это действительно похоже на то, что требуется метод расширения.

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();
}

EDIT

Вам не нужна структура 3.5, чтобы иметь методы расширения. Они с радостью будут работать над компилятором 3.0, нацеленным на 2.0

.

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

2 голосов
/ 19 марта 2009

Мне кажется, вы неправильно понимаете, что делает Using.

Это просто синтаксический сахар для замены

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

Ваше использование в AddFileToManipulate является избыточным. Я бы настроил список потоков памяти в конструкторе PdfDocumentManipulator, а затем вызвал бы метод dispose PdfDocumentManipulator dispose для всех потоков памяти.

...