Подтвердить что ты не робот

Возврат потока памяти из функции

В ваших мнениях, лучше ли вернуть вновь выделенный поток памяти из функции или передать ее в функцию? Например,

void Foo(MemoryStream m) 
{ 
   m.Write(somebuffer, 0, somebuffer.Length); 
}

или

void MemoryStream Foo()
{
    MemoryStream retval = new MemoryStream();
    retval.Write(somebuffer, 0, somebuffer.Length);
    return retval;
}
4b9b3361

Ответ 1

Это немного похоже на вопрос, следует ли вам возвращать строку из метода или принимать StringBuilder и добавлять к ней. Ответ зависит от того, какой вариант использования.

Возможно ли, что вызывающий абонент захочет вызвать ваш метод с существующим потоком, содержащим некоторые данные? Может, они захотят назвать это несколько раз, используя тот же поток? Если это так, версия, использующая MemoryStream, будет более эффективной. С другой стороны, если они хотят получить данные только один раз, возвращение его как MemoryStream (или, проще говоря, в виде байтового массива) может быть более подходящим.

К сожалению, из описания мы не можем сказать, что происходит. Конечно, вы можете реализовать как перегрузку, так и перезвонить друг другу.

Ответ 2

Передача потока памяти в функцию и возврат поток памяти для функции не должен использоваться взаимозаменяемо. Методы, которые вы описываете, служат двум различным целям.

  • Передача чего-либо функции - это когда вы хотите, чтобы функция что-то делала с параметром.

  • Возвращение чего-то из функции - это когда вызывающий объект должен что-то делать с результатом.

Вы говорите о двух разных вещах, яблоках и апельсинах.

Ответ 3

Я всегда передавал поток в функцию. Это позволяет работать с любым потоком вызывающего абонента, например, прямо в файл без какой-либо буферизации.

Ответ 4

Вы можете безопасно вернуть его из функции. Вы должны вызвать Dispose() или поместить его в предложение using, потому что оно реализует IDisposable.

Ответ 5

Ваш второй лучше. Я всегда стараюсь избегать мутирования объектов внутри функций, если это вообще возможно.

Ответ 6

После некоторой мысли, я думаю, что это сводится к предполагаемой семантике метода Foo. Это:

  • Операция, которая создает поток (например. File.Open())
  • Операция, которая изменяет поток (например. something.WriteXml())

Если ответ "создает поток", пусть он возвращает поток. Если он изменяет поток, передайте поток.

Если ответ "некоторые из обоих", может иметь смысл разделить метод так, чтобы он имел только одну ответственность.

Ответ 7

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

using (MemoryStream ms = Foo())
{
  //Do Stuff here.
}

Самое главное - не забыть правильно распоряжаться им.

Ответ 8

Я бы предпочел бы, чтобы введенная форма. Он удаляет прямую связь между вашим кодом и MemoryStream и делает его более проверяемым.

public void Foo(Stream stream)
{
    stream.Write(somebuffer, 0, somebuffer.Length);
}

Теперь я могу проверить Foo с любым классом, который реализует Stream, включая класс mock.

Как правило, я делал бы инъекцию в конструкторе класса, а не по отдельным методам, но идея в основном такая же.

public class FooClass
{
   public Stream FooStream { get; private set; }

   public FooClass() : this(null) { }

   public FooClass( Stream stream )
   {
       // provide a default if not specified
       this.FooStream = stream ?? new MemoryStream();
   }

   public void Foo()
   {
       this.FooStream.Write( somebuffer, 0, somebuffer.Length );
   }
}

Ответ 9

Я бы склонен к первому по двум причинам:

  • Семантика того, кто "владеет" потоком памяти, понятна. Вызывающий вызывал его, поэтому его вызывало, чтобы избавиться от него (это больше проблема с другими типами потоков, которые удерживаются на неуправляемых ресурсах).
  • Foo может использоваться в сочетании с другими методами, которые работают с вашим потоком.

Тем не менее, если основной целью Foo является метод factory для MemoryStreams (аналогично файлу File.Open и т.д.), второй подход имеет больше смысла.

Ответ 10

Поскольку потоки - это ресурсы, требующие явного удаления (память, файл, сеть), лучше всего применять подход RAII к их обработке. Это означает, что функция, которая их инициализирует, должна быть ответственна за выпуск (у нас есть "использование" keyord в С# только для этого). Чтобы включить этот шаблон, я говорю о принятии потока в качестве параметра. Таким образом, вызывающий может решить, когда создавать и удалять поток. В то время как вы на нем, ваш метод принимает любую реализацию потока; не похоже, что он должен работать только для MemoryStream.