Daniel Park
Daniel Park

Reputation: 4021

.Net streams: Returning vs Providing

I have always wondered what the best practice for using a Stream class in C# .Net is. Is it better to provide a stream that has been written to, or be provided one? i.e:

public Stream DoStuff(...)
{
    var retStream = new MemoryStream();
    //Write to retStream
    return retStream;
}

as opposed to;

public void DoStuff(Stream myStream, ...)
{
    //write to myStream directly
}

I have always used the former example for sake of lifecycle control, but I have this feeling that it a poor way of "streaming" with Stream's for lack of a better word.

Upvotes: 13

Views: 1503

Answers (3)

Neil
Neil

Reputation: 7437

100% the second one. You don't want to make assumptions about what kind of stream they want. Do they want to stream to the network or to disk? Do they want it to be buffered? Leave these up to them.

They may also want to reuse the stream to avoid creating new buffers over and over. Or they may want to stream multiple things end-to-end on the same stream.

If they provide the stream, they have control over its type as well as its lifetime. Otherwise, you might as well just return something like a string or array. The stream isn't really giving you any benefit over these.

Upvotes: 0

Andrew Shepherd
Andrew Shepherd

Reputation: 45252

I see the benefit of Streams is that you don't need to know what you're streaming to.

In the second example, your code could be writing to memory, it could be writing directly to file, or to some network buffer. From the function's perspective, the actual output destination can be decided by the caller.

For this reason, I would prefer the second option.

The first function is just writing to memory. In my opinion, it would be clearer if it did not return a stream, but the actual memory buffer. The caller can then attach a Memory Stream if he/she wishes.

public byte[] DoStuff(...)
{
    var retStream = new MemoryStream();
    //Write to retStream
    return retStream.ToArray();
}

Upvotes: 6

ChristopheD
ChristopheD

Reputation: 116147

I would prefer "the second way" (operate on a provided stream) since it has a few distinct advantages:

  • You can have polymorphism (assuming as evidenced by your signature you can do your operations on any type of Stream provided).
  • It's easily abstracted into a Stream extension method now or later.
  • You clearly divide responsibilities. This method should not care on how to construct a stream, only on how to apply a certain operation to it.

Also, if you're returning a new stream (option 1), it would feel a bit strange that you would have to Seek again first in order to be able to read from it (unless you do that in the method itself, which is suboptimal once more since it might not always be required - the stream might not be read from afterwards in all cases). Having to Seek after passing an already existing stream to a method that clearly writes to the stream does not seem so awkward.

Upvotes: 12

Related Questions