I have tried to pass stream as an argument but I am not sure which way is "the best" so would like to hear your opinion / suggestions to my code sample
I personally prefer Option 3, but I have never seen it done this way anywhere else.
Option 1 is good for small streams (and streams with a known size)
Option 2_1 and 2_2 would always leave the "Hander" in doubt of who has the responsibility for disposing / closing.
public interface ISomeStreamHandler
{
// Option 1
void HandleStream(byte[] streamBytes);
// Option 2
void HandleStream(Stream stream);
// Option 3
void HandleStream(Func<Stream> openStream);
}
public interface IStreamProducer
{
Stream GetStream();
}
public class SomeTestClass
{
private readonly ISomeStreamHandler _streamHandler;
private readonly IStreamProducer _streamProducer;
public SomeTestClass(ISomeStreamHandler streamHandler, IStreamProducer streamProducer)
{
_streamHandler = streamHandler;
_streamProducer = streamProducer;
}
public void DoOption1()
{
var buffer = new byte[16 * 1024];
using (var input = _streamProducer.GetStream())
{
using (var ms = new MemoryStream())
{
int read;
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
{
ms.Write(buffer, 0, read);
}
_streamHandler.HandleStream(ms.ToArray());
}
}
}
public void DoOption2_1()
{
_streamHandler.HandleStream(_streamProducer.GetStream());
}
public void DoOption2_2()
{
using (var stream = _streamProducer.GetStream())
{
_streamHandler.HandleStream(stream);
}
}
public void DoOption3()
{
_streamHandler.HandleStream(_streamProducer.GetStream);
}
}
You may not realize it, but you are attempting to implement the pipeline design pattern. As a starting point, consider taking a look at:
With regards to your implementation, I recommend that you go with option #2:
public interface IStreamHandler
{
void Process(Stream stream);
}
With regards to object lifetime, it is my belief that:
Dispose
IStreamHandler
did not call Dispose
(now you can chain handlers together much like you would in Unix pipes)THIRD-PARTY SOLUTIONS
Building a pipeline solution can be fun, but it is also worth noting that there are existing products on the market:
ADDITIONAL NOTES
There is a design issue related to your proposed Option 2:
void Process(Stream stream);
In Unix Pipes you can chain a number of applications together by taking the output of one program and make it the input of another. If you were to build a similar solution using Option 2, you will run into problems if you are using multiple handlers and your data Stream
is forward only (i.e. stream.CanSeek=False
).
Option 2_2 is the standard way of dealing with disposable resources.
Your SomeTestClass
instance asks the producer for a stream - then SomeTestClass
owns a stream and is responsible for cleaning up.
Options 3 and 2_1 rely on a different object to clean up the resource owned by SomeTestClass
- this expectation might not be met.
Option 1 is jut copying a stream's content to another stream - I don't see any benefits in doing that.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With