我有一个获取一系列项目的函数:
List<MyType> GetPage(int pageNr) {...}
要获得所有可用的项目,您可以执行以下操作:
IEnumerable<MyType> FetchMyItems()
{
int pageNr = 0;
var fetchedItems = GetPage(pageNr);
while (fetchedItems.Any()
{ // there are items to return
// yield return the fetched items:
foreach (var fetchedItem in fetchedItems)
yield return fetchedItems;
// get the next page
++pageNr;
fetchedItems = GetPage(pageNr)
}
}
使用此方法,我的用户不再需要每页获取项目,如果他们只需要几个项目,则只会获取第一页。当需要更多项目时,将自动获取更多页面。缺点当然是我有时会获取一些不会被使用的物品。
所以我有以下GetPage:
async Task<List<MyType>> GetPageAsync(int pageNr) {...}
根据我从IEnumerable的理解,它不会创建结果序列,它只会创建枚举此序列的可能性。
这个枚举是使用&#39; foreach&#39;明确完成的,或隐式使用LINQ函数,例如ToList&#39; ToArray&#39;,还有类似&#39;的功能。 FirstOrDefault&#39;,&#39; Any&#39;,Sum
。
var fetchItemTasks = FetchMyItemsAsync();
foreach (var fetchItemTask in fetchedItemTasks)
{
MyType fetchedItem = await fetchItemTask;
Process(fetchedItem);
}
或者,如果你做这个低级别:
var myitemsEnumerable = fetchMyItemsAsync();
// don't await yet, only create the possibility to enumerate
var enumerator = myItemsEnumerable.GetEnumerator();
while (enumerator.MoveNext())
{ // there is an item available in current:
Task<MyType> task = enumerator.Current;
return task;
}
看看这个,似乎该函数不应该返回Task<IEnumerable<MyType>>
而是IEnumerable<Task<MyType>>
,如果你想访问一个你必须等待的元素。
因此,返回枚举可等待项的可能性的函数本身并不是异步的。您没有等待可枚举,可以在不访问数据库等慢速提供程序的情况下创建此可枚举。可枚举序列中的项目是等待的:
IEnumerable<Task<MyType>> FetchMyItems()
{
int pageNr = 0;
Task<List<MyType>> fetchItemTask = GetPageAsync(pageNr);
现在?如果我await fetchItemTask
,那些物品已经在当地没有任何东西需要等待了。如果我fetchItemTask.Wait()
,则功能块。
答案 0 :(得分:0)
您的async / await模式的实现看起来不正确。
GetPageAsync
签名没问题:
async Task<List<MyType>> GetPageAsync(int pageNr) {...}
现在,如果要异步调用此方法,则必须使用await
关键字,这将暂停执行方法并将控制权返回给其调用方,直到GetPageAsync
结果准备就绪:
List<MyType> items = await GetPageAsync(pageNr);
或
Task<List<MyType>> getPageTask = GetPageAsync(pageNr);
// Some other stuff
List<MyType> items = await getPageTask;
但请注意,await
关键字只能在自身为async
的方法中使用。
可能我没有意识到你的应用程序异步模型的整个想法,但无论如何,我建议先看看这个MSDN article on asynchronous programming with async/await。