传递流的最佳方法是什么?

时间:2013-12-11 13:49:03

标签: c# stream arguments

我试图将流作为参数传递,但我不确定哪种方式是“最好的”,所以我希望听到您对我的代码示例的意见/建议

我个人更喜欢三种选择,但我更新看到它在其他地方以这种方式完成。

选项1适用于小流(以及已知大小的流)

选项2_1和2_2总是让“管理员”怀疑谁有责任处置/关闭。

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

3 个答案:

答案 0 :(得分:3)

选项2_2是处理可支配资源的标准方式。

您的SomeTestClass实例要求制作人提供一个流 - 然后SomeTestClass 拥有一个流,并负责清理。

选项3和2_1依赖于不同的对象来清理SomeTestClass拥有的资源 - 可能无法满足此期望。

选项1将流的内容复制到另一个流 - 我没有看到这样做有什么好处。

答案 1 :(得分:1)

您可能没有意识到,但您正在尝试实施管道设计模式。作为起点,请考虑一下:

关于您的实施,我建议您使用选项#2:

public interface IStreamHandler
{
    void Process(Stream stream);
}

关于对象的生命周期,我相信:

  • 实现应该如何处理调用Dispose
  • 如果IStreamHandler没有调用Dispose(现在你可以将处理程序链接在一起,就像在Unix管道中一样),你的解决方案会更灵活。

第三方解决方案

构建管道解决方案可能很有趣,但值得注意的是市场上现有产品:

其他说明

存在与您提议的选项2 相关的设计问题:

void Process(Stream stream);

Unix Pipes中,您可以通过获取一个程序的输出并将其作为另一个程序的输入来将多个应用程序链接在一起。如果您使用选项2 构建类似的解决方案,如果您使用多个处理程序并且您的数据Stream仅向前(即stream.CanSeek=False),则会遇到问题。

答案 2 :(得分:0)

传递IStream,并且流在哪里生成实施IDisposable。 处理流的责任在于创建它的对象。