IAsyncEnumerable 的传递?
Pass-through for IAsyncEnumerable?
我想知道是否有一种方法可以将函数写入 "pass through" IAsyncEnumerable...也就是说,该函数将调用另一个 IAsyncEnumerable 函数并产生所有结果,而无需编写foreach
要做吗?
我发现自己经常写这个 Code Pattern。这是一个例子:
async IAsyncEnumerable<string> MyStringEnumerator();
async IAsyncEnumerable<string> MyFunction()
{
// ...do some code...
// Return all elements of the whole stream from the enumerator
await foreach(var s in MyStringEnumerator())
{
yield return s;
}
}
无论出于何种原因(由于分层设计),我的函数 MyFunction
想要调用 MyStringEnumerator
,但随后会在没有干预的情况下产生所有内容。我必须继续编写这些 foreach
循环才能做到这一点。如果它是 IEnumerable
,我会 return IEnumerable
。如果是 C++,我可以写一个宏来完成它。
最佳做法是什么?
If it were an IEnumerable I would return the IEnumerable.
嗯,你可以用 IAsyncEnumerable
做同样的事情(注意 async
被删除):
IAsyncEnumerable<string> MyFunction()
{
// ...do some code...
// Return all elements of the whole stream from the enumerator
return MyStringEnumerator();
}
但是,这里有一个重要的语义考虑因素。调用枚举器方法时,...do some code...
会立即执行,而当枚举器被枚举时不会。
// (calling code)
var enumerator = MyFunction(); // `...do some code...` is executed here
...
await foreach (var s in enumerator) // it's not executed here when getting the first `s`
...
对于同步和异步枚举都是如此。
如果你希望...do some code...
在枚举器被枚举时执行,那么你需要使用foreach
/yield
循环来获得延迟执行语义:
async IAsyncEnumerable<string> MyFunction()
{
// ...do some code...
// Return all elements of the whole stream from the enumerator
await foreach(var s in MyStringEnumerator())
yield return s;
}
如果你也想使用同步可枚举的延迟执行语义,你将不得不在同步世界中使用相同的模式:
IEnumerable<string> ImmediateExecution()
{
// ...do some code...
// Return all elements of the whole stream from the enumerator
return MyStringEnumerator();
}
IEnumerable<string> DeferredExecution()
{
// ...do some code...
// Return all elements of the whole stream from the enumerator
foreach(var s in MyStringEnumerator())
yield return s;
}
从调用方法返回 Task<IAsyncEnumerable<Obj>>
似乎有效
async IAsyncEnumerable<string> MyStringEnumerator();
async Task<IAsyncEnumerable<string>> MyFunction()
{
await Something();
return MyStringEnumerator();
}
然后您需要等待 MyFunction()。所以在异步 foreach 中使用将是
await foreach (string s in await MyFunction()) {}
我想知道是否有一种方法可以将函数写入 "pass through" IAsyncEnumerable...也就是说,该函数将调用另一个 IAsyncEnumerable 函数并产生所有结果,而无需编写foreach
要做吗?
我发现自己经常写这个 Code Pattern。这是一个例子:
async IAsyncEnumerable<string> MyStringEnumerator();
async IAsyncEnumerable<string> MyFunction()
{
// ...do some code...
// Return all elements of the whole stream from the enumerator
await foreach(var s in MyStringEnumerator())
{
yield return s;
}
}
无论出于何种原因(由于分层设计),我的函数 MyFunction
想要调用 MyStringEnumerator
,但随后会在没有干预的情况下产生所有内容。我必须继续编写这些 foreach
循环才能做到这一点。如果它是 IEnumerable
,我会 return IEnumerable
。如果是 C++,我可以写一个宏来完成它。
最佳做法是什么?
If it were an IEnumerable I would return the IEnumerable.
嗯,你可以用 IAsyncEnumerable
做同样的事情(注意 async
被删除):
IAsyncEnumerable<string> MyFunction()
{
// ...do some code...
// Return all elements of the whole stream from the enumerator
return MyStringEnumerator();
}
但是,这里有一个重要的语义考虑因素。调用枚举器方法时,...do some code...
会立即执行,而当枚举器被枚举时不会。
// (calling code)
var enumerator = MyFunction(); // `...do some code...` is executed here
...
await foreach (var s in enumerator) // it's not executed here when getting the first `s`
...
对于同步和异步枚举都是如此。
如果你希望...do some code...
在枚举器被枚举时执行,那么你需要使用foreach
/yield
循环来获得延迟执行语义:
async IAsyncEnumerable<string> MyFunction()
{
// ...do some code...
// Return all elements of the whole stream from the enumerator
await foreach(var s in MyStringEnumerator())
yield return s;
}
如果你也想使用同步可枚举的延迟执行语义,你将不得不在同步世界中使用相同的模式:
IEnumerable<string> ImmediateExecution()
{
// ...do some code...
// Return all elements of the whole stream from the enumerator
return MyStringEnumerator();
}
IEnumerable<string> DeferredExecution()
{
// ...do some code...
// Return all elements of the whole stream from the enumerator
foreach(var s in MyStringEnumerator())
yield return s;
}
从调用方法返回 Task<IAsyncEnumerable<Obj>>
似乎有效
async IAsyncEnumerable<string> MyStringEnumerator();
async Task<IAsyncEnumerable<string>> MyFunction()
{
await Something();
return MyStringEnumerator();
}
然后您需要等待 MyFunction()。所以在异步 foreach 中使用将是
await foreach (string s in await MyFunction()) {}