Дилемма проектирования API об ответственности за очистку

#c# #api

#c# #API

Вопрос:

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

Вот пример:

 // public method of library
public class MyObject
{
   public void Read(System.IO.Stream stream)
   {
      ...
   }
   ...
}
  

Если ответственность будет нести вызывающий, клиентский код должен выглядеть следующим образом:

 using (FileStream file = new FileStream(...))
{
   MyObject myObject = new MyObject();
   myObject.Read(file);
}
  

Комментарии:

1. Вызывающий должен нести ответственность за распоряжение ресурсами, которые он запрашивает. (ИМХО)

Ответ №1:

Я бы сказал, что нормальное «владение» принадлежит тому, кто создает ресурс для начала, — то есть вызывающему ваш метод. Помимо всего прочего, кто сказал, что вызывающий хочет избавиться от потока после чтения? Возможно, они хотят перемотать его и передать чему-то другому.

Обычно я нервничаю из-за удаления всего, что я явно не создал. Конечно, есть исключения из этого — Bitmap(Stream) конструктор фактически становится владельцем потока и предполагает, что вы будете распоряжаться растровым изображением, которое, в свою очередь, будет распоряжаться потоком … но я бы сказал, что это скорее исключение, чем правило.

Комментарии:

1. Что насчет того, когда метод возвращает поток, а не передает в потоке? Похоже, что по умолчанию вызывающий объект является владельцем, даже если он не создавал поток . Например. Если я вызываю File . Open() тогда я несу ответственность за удаление потока, который он возвращает, даже если я его не создавал. Кажется, что вызывающий объект всегда является владельцем, независимо от того, передаем ли мы поток как параметр или получаем поток в качестве возврата, поскольку, как вы указали, это максимизирует возможность повторного использования, поскольку вызывающий объект может решить, когда утилизировать поток. Интересует ваше мнение о сценарии возврата потока.

2. @AaronLS: Да, в большинстве случаев вызывающий становится «владельцем» в этой ситуации.

Ответ №2:

В общем, вызывающий должен выполнить очистку, поскольку вы не знаете, действительно ли вызывающий закончил со своим объектом.

Однако, если ваш метод «потребляет» объект таким образом, что вызывающий объект не может использовать его снова (например, если он считывает поток, не подлежащий поиску), тогда вы можете захотеть избавиться от него самостоятельно.