我有一个工作流程,试图实现以下目标:
- 一个接受回调函数的方法,该方法内部生成一个
Stream
,该方法的调用者可以使用回调函数以任何希望的方式处理Stream
- 在特定情况下,调用者使用回调函数从
Stream
中生成IAsyncEnumerable
。
下面是一个最小化的重现示例:
class Program
{
private static async Task<Stream> GetStream()
{
var text =
@"Multi-line
string";
await Task.Yield();
var bytes = Encoding.UTF8.GetBytes(text);
return new MemoryStream(bytes);
}
private static async Task<T> StreamData<T>(Func<Stream, T> streamAction)
{
await using var stream = await GetStream();
return streamAction(stream);
}
private static async Task StreamData(Func<Stream, Task> streamAction)
{
await using var stream = await GetStream();
await streamAction(stream);
}
private static async IAsyncEnumerable<string> GetTextLinesFromStream(Stream stream)
{
using var reader = new StreamReader(stream);
var line = await reader.ReadLineAsync();
while (line != null)
{
yield return line;
line = await reader.ReadLineAsync();
}
}
private static async Task Test1()
{
async Task GetRecords(Stream str)
{
await foreach(var line in GetTextLinesFromStream(str))
Console.WriteLine(line);
}
await StreamData(GetRecords);
}
private static async Task Test2()
{
await foreach(var line in await StreamData(GetTextLinesFromStream))
Console.WriteLine(line);
}
static async Task Main(string[] args)
{
await Test1();
await Test2();
}
}
这里,方法Test1
可以正常工作,而Test2
则无法运行,出现Stream is not readable
的错误。问题在于第二种情况下,当代码真正处理流时,该流已经被关闭了。
可以推测,第一种情况与第二种情况的区别在于,在第一种情况下,读取流时仍处于可处理的stream
上下文中,而在第二种情况下我们已经超出了该上下文。
然而,我认为第二种情况也是有效的——至少我觉得它非常符合C#语言特色。是否有任何遗漏的内容可以使第二种情况也能正常工作吗?
StreamData
方法的覆盖。无论如何,我将接受这个作为答案。 - zidour