C# 让溪流流过的最好方法是什么
我曾尝试将stream作为一个参数传递,但我不确定哪种方式是“最好的”,因此希望听到您对我的代码示例的意见/建议 我个人更喜欢选项3,但在其他地方我从未见过这样做 选项1适用于小型流(以及已知大小的流) 选项2_1和选项2_2总是让“交易人”怀疑谁有责任处置/交割C# 让溪流流过的最好方法是什么,c#,stream,arguments,C#,Stream,Arguments,我曾尝试将stream作为一个参数传递,但我不确定哪种方式是“最好的”,因此希望听到您对我的代码示例的意见/建议 我个人更喜欢选项3,但在其他地方我从未见过这样做 选项1适用于小型流(以及已知大小的流) 选项2_1和选项2_2总是让“交易人”怀疑谁有责任处置/交割 public interface ISomeStreamHandler { // Option 1 void HandleStream(byte[] streamBytes); // Option 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);
}
}
公共接口处理程序
{
//选择1
void HandleStream(字节[]流字节);
//选择2
无效手流(溪流);
//选择3
无效手流(Func openStream);
}
公共接口IStreamProducer
{
Stream GetStream();
}
公共类SomeTestClass
{
私有只读流处理器_streamHandler;
私有只读IStreamProducer\u streamProducer;
公共SomeTestClass(ISomeStreamHandler streamHandler、IsStreamProducer streamProducer)
{
_streamHandler=streamHandler;
_streamProducer=streamProducer;
}
公共无效选项1()
{
var buffer=新字节[16*1024];
使用(var输入=_streamProducer.GetStream())
{
使用(var ms=new MemoryStream())
{
int-read;
而((read=input.read(buffer,0,buffer.Length))>0)
{
ms.Write(缓冲区,0,读取);
}
_streamHandler.HandleStream(ToArray女士());
}
}
}
公共无效选项2_1()
{
_streamHandler.HandleStream(_streamProducer.GetStream());
}
公共无效选项2_2()
{
使用(var stream=\u streamProducer.GetStream())
{
_streamHandler.手流(流);
}
}
公共无效选项3()
{
_streamHandler.HandleStream(_streamProducer.GetStream);
}
}
传递一个IStream
,并在流的起始位置执行IDisposable
。
处理流的责任在于创建它的对象。选项2\u 2是处理可处置资源的标准方法 您的
SomeTestClass
实例向生产者请求一个流,然后SomeTestClass
拥有一个流并负责清理
选项3和21依赖不同的对象来清理SomeTestClass
所拥有的资源-可能无法满足此期望
选项1只是将一个流的内容复制到另一个流——我看不出这样做有什么好处。您可能没有意识到这一点,但您正在尝试实现管道设计模式。作为一个出发点,考虑一下:
- (其他良好的参考资料??)
- 实现在处理调用
Dispose
- 如果
没有调用IStreamHandler
,您的解决方案将更加灵活(现在您可以像在Unix管道中一样将处理程序链接在一起)Dispose
在中,您可以通过将一个程序的输出作为另一个程序的输入,将多个应用程序链接在一起。如果您要使用选项2构建类似的解决方案,那么如果您使用多个处理程序,并且您的数据
Stream
仅为正向(即Stream.CanSeek=False
),您将遇到问题。选项3仅使用“MemoryStream”作为将流转换为字节数组的手段。-因此,这不是将流内容解析到另一个流的问题;如果您被要求在何处执行“void HandleStream(Stream);”您将假定您的实现没有责任关闭/处理流?@JakobDyrby-仍然,选项3是从流读取、写入内存流,并转换为字节[]
。为什么不直接从流中读取,然后使用缓冲区呢?@JakobDyrby:是的。如果一次性资源(不仅仅是流)作为参数传递给我的方法,我不会假设我应该关闭它。事实上,我会说我有责任不关闭它。我不知道是谁在呼叫我,我不知道呼叫我的人是否需要进一步访问该流-因此我有义务让它保持打开状态。@JakobDyrby根据经验,关键字是所有权。无论谁拥有IDisposable
实例,都有责任关闭它。谢谢!我将阅读该设计模式。但是现在;请你详细说明你认为谁有责任关闭这家公司。我应该使用选项2_1或选项2_2中所示的界面吗?我会选择:DoOption2_2。更重要的是:(1)与您的实现保持一致,(2)确保在意外引发异常时释放所有资源。因此,FileInfo对象有责任关闭“fi.OpenRead()”之后的流,但事实并非如此。请参阅@dcastro的评论,“根据经验,关键词是所有权。无论谁拥有IDisposable实例,都有责任关闭它。”
public interface IStreamHandler
{
void Process(Stream stream);
}
void Process(Stream stream);