我有一个工作流程,我尝试执行以下操作:
- 一个接受回调的方法,它在内部产生 a
Stream
并且该方法的调用者可以使用回调来处理Stream
他们想要的任何方式 IAsyncEnumerable
在一种特殊情况下,调用者使用回调从 Stream中生成一个。
我在下面创建了一个最小的复制示例:
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# 习惯。为了让第二个案例也能正常工作,我还有什么遗漏吗?