C# IAsynceneumber方法中的正确处理?
这个问题的答案可能是不可能的,但问题是:假设您有一个C方法来使用C# IAsynceneumber方法中的正确处理?,c#,iasyncenumerable,iasyncdisposable,C#,Iasyncenumerable,Iasyncdisposable,这个问题的答案可能是不可能的,但问题是:假设您有一个C方法来使用TextReader中返回IAsyncEnumerable的行。在iasyncumerator上调用DisposeAsync时,如何确保TextReader已被释放?或者这是您需要编写自定义实现才能实现的吗?只需在异步迭代器中使用try-finally块,或者更简单地说是使用块的,调用方完成枚举后,文本阅读器将立即被释放。枚举是正常完成,还是由于异常或中断而提前完成,这无关紧要 static async Task Main(stri
TextReader
中返回IAsyncEnumerable
的行。在iasyncumerator
上调用DisposeAsync
时,如何确保TextReader
已被释放?或者这是您需要编写自定义实现才能实现的吗?只需在异步迭代器中使用try-finally块,或者更简单地说是使用块的,调用方完成枚举后,文本阅读器将立即被释放。枚举是正常完成,还是由于异常或中断而提前完成,这无关紧要
static async Task Main(string[] args)
{
await foreach (var line in GetLines())
{
Console.WriteLine(line);
}
}
private static async IAsyncEnumerable<string> GetLines()
{
var reader = new StringReader("Line1\nLine2\nLine3");
try
{
while (true)
{
var line = await reader.ReadLineAsync();
if (line == null) break;
yield return line;
}
}
finally
{
reader.Dispose();
Console.WriteLine("Disposed");
}
}
static async Task Main(字符串[]args)
{
等待foreach(GetLines()中的变量行)
{
控制台写入线(行);
}
}
私有静态异步IAsyncEnumerable GetLines()
{
变量读取器=新的StringReader(“Line1\nLine2\nLine3”);
尝试
{
while(true)
{
var line=wait reader.ReadLineAsync();
如果(line==null)中断;
收益率回归线;
}
}
最后
{
reader.Dispose();
控制台。写入线(“已处置”);
}
}
输出:
第1行
第2行
第3行
处置
只需在异步迭代器中使用try finally块,或者更简单地使用using
块,调用方完成枚举后,TextReader
就会被释放。枚举是正常完成,还是由于异常或中断而提前完成,这无关紧要
static async Task Main(string[] args)
{
await foreach (var line in GetLines())
{
Console.WriteLine(line);
}
}
private static async IAsyncEnumerable<string> GetLines()
{
var reader = new StringReader("Line1\nLine2\nLine3");
try
{
while (true)
{
var line = await reader.ReadLineAsync();
if (line == null) break;
yield return line;
}
}
finally
{
reader.Dispose();
Console.WriteLine("Disposed");
}
}
static async Task Main(字符串[]args)
{
等待foreach(GetLines()中的变量行)
{
控制台写入线(行);
}
}
私有静态异步IAsyncEnumerable GetLines()
{
变量读取器=新的StringReader(“Line1\nLine2\nLine3”);
尝试
{
while(true)
{
var line=wait reader.ReadLineAsync();
如果(line==null)中断;
收益率回归线;
}
}
最后
{
reader.Dispose();
控制台。写入线(“已处置”);
}
}
输出:
第1行
第2行
第3行
处置
实际上,处置TextReader
并不是枚举的工作,而是创建TextReader
的人的工作。通常情况下,您会期望代码在自己的任务中使用自己的。从理论上讲,您可以将读者传递给枚举器,让它负责,但这将减少它实际有用的场景。从概念上讲,枚举数不同于它们所枚举的内容。请注意,如果您有一个迭代器方法本身创建TextReader
,那么您所需要做的就是确保它使用var reader=new TextReader(…)
;编译器魔术将迭代器的使用块转换为dispose上调用的东西,就像非异步迭代器一样。实际上,处置TextReader
不是枚举的工作,而是创建TextReader
的任何人的工作。通常情况下,您会期望代码在自己的任务中使用自己的。从理论上讲,您可以将读者传递给枚举器,让它负责,但这将减少它实际有用的场景。从概念上讲,枚举数不同于它们所枚举的内容。请注意,如果您有一个迭代器方法本身创建TextReader
,那么您所需要做的就是确保它使用var reader=new TextReader(…)
;编译器魔术将迭代器的using块转换为dispose上调用的内容,就像非异步迭代器一样。如果foreach是一个永不结束的无限循环,则不会释放枚举器,也不会调用finally块。这是我能想到的唯一一种情况。另一种情况是,如果一个有缺陷或恶意的调用方(通过调用该方法)创建了一个枚举数,然后在静态字段中保留对它的引用,以防止它被垃圾收集。这种可能性也适用于普通(非异步)枚举器/枚举器。我想的实际情况是,如果有人因为获得了所需的数据而中断循环。(我不太关心臭虫/恶意。)本案例已涵盖。中断foreach
循环会导致立即处理循环中使用的枚举数,从而导致在迭代器中调用finally块。如果foreach是一个永不结束的无限循环,则不会处理枚举数,也不会调用finally块。这是我能想到的唯一一种情况。另一种情况是,如果一个有缺陷或恶意的调用方(通过调用该方法)创建了一个枚举数,然后在静态字段中保留对它的引用,以防止它被垃圾收集。这种可能性也适用于普通(非异步)枚举器/枚举器。我想的实际情况是,如果有人因为获得了所需的数据而中断循环。(我不太关心臭虫/恶意。)本案例已涵盖。中断foreach
循环会立即处理循环中使用的枚举数,从而在迭代器中调用finally块。