C# / .NET的惰性流

6

有人知道在.net中是否有懒加载流的实现吗?换句话说,我想创建一个像这样的方法:

public Stream MyMethod() {
    return new LazyStream(...whatever parameters..., delegate() {
        ... some callback code.
    });
}

当我的其他代码调用MyMethod()以返回检索流时,实际上在没有人尝试从流中读取数据之前,它不会执行任何操作。通常的方法是将MyMethod作为参数传递流参数,但在我的情况下,这种方法行不通(我想将返回的流给一个MVC FileStreamResult)。
进一步解释一下,我要创建一系列分层转换,因此:
数据库结果集 =(转换为)=> 字节流 =(链接到)=> GZipStream =(传递给)=> FileStreamResult构造函数。
结果集可能很大(GB),因此我不想将结果缓存在MemoryStream中,然后将其传递给GZipStream构造函数。相反,我想在GZipStream请求数据时从结果集中获取数据。

实现一个IEnumerable<byte>或类似的东西对你不起作用吗? - Jason Kleban
理论上,如果有一个流的构造函数接受IEnumerable<byte>,那么它是可以的。虽然这感觉非常低效(但过早优化是万恶之源)。 - erikkallen
3个回答

5
大多数流实现本质上都是惰性流。通常情况下,除了一些额外的“超读”以允许缓冲发生(这使得流使用更快),任何流都不会从其源中读取信息,直到被流的用户请求。
如果您需要完全的惰性流实现,那么很容易制作一个Stream实现,它在必要时不进行读取,只需重写Read以打开底层资源并在使用时从中读取即可。只需重写Read、CanRead、CanWrite和CanSeek即可。

0
在你的Stream类中,你需要实现System.IO.Stream的几个方法,包括Read方法。
在这个方法中你可以自由发挥。如果你选择调用一个委托,这也取决于你,当然你可以将这个委托作为构造函数的参数之一传递进去。至少这是我会这样做的。
不幸的是,仅仅实现Read方法是不够的,而且你的委托也无法覆盖其他必需的方法。

是的,我知道,我只是希望有人已经编写了这个类。 - erikkallen

0

这个答案(https://dev59.com/62Eh5IYBdhLWcg3ww1xp#22048857)链接到关于如何编写自己的流类的文章

引用答案:

生产者向流中写入数据,消费者读取数据。中间有一个缓冲区,以便生产者可以“预先写入”一点数据。您可以定义缓冲区的大小。

引用原始来源:

您可以将ProducerConsumerStream视为具有流接口的队列。在内部,它实现为循环缓冲区。两个索引跟踪缓冲区内插入和删除点。字节写入Head索引,并从Tail索引中删除。

如果Head回绕到Tail,则缓冲区已满,生产者必须等待一些字节被读取才能继续写入。同样,如果Tail追上Head,则消费者必须等待字节被写入才能继续进行。

本文继续描述了一些指针环绕的奇怪情况,并提供了完整的代码示例。

这个链接已经失效了。 - Puppy
1
谢谢@Puppy,下次遇到死链接可以尝试使用Wayback Machine:https://web.archive.org/web/20151210235510/http://www.informit.com/guides/content.aspx?g=dotnet&seqNum=852 - drzaus

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接