public static async Task<T> FirstIfNotNullOrEmptyAsync<T>(this Task<IEnumerable<T>> obj) where T : class
{
var first = await Task.WhenAny(obj);
return first?.Result?.FirstOrDefault() ?? null;
}
以下是另外两种显示完整
的方法主要方法 (在这种情况下,只返回集合中的项目或集合为空)
private async Task<IEnumerable<T>> fetchRecordsAsync(SqlCommand SqlCommand, bool isSingleRecord)
{..some code...}
以下是获取集合并仅传递T:
的调用者protected async Task<T> GetSingleRecord(SqlCommand SqlCommand)
{
return await fetchRecordsAsync(SqlCommand, true).FirstIfNotNullOrEmptyAsync();
}
这是使用IEnumerable的异步扩展的正确方法,还是会进行同步?
我真的需要创建另一个任务(第一个)吗?
答案 0 :(得分:3)
这真的是异步吗?
是的。 await Task.WhenAny
将返回完成的第一个任务。在此类任务(已完成的任务)上使用.Result
不会导致同步等待。
Task.WhenAny
,你的方法可以这样简化:
public static async Task<T> FirstIfNotNullOrEmptyAsync<T>(
this Task<IEnumerable<T>> obj) where T : class
{
var result = await obj;
return result?.FirstOrDefault();
}
答案 1 :(得分:2)
它将以异步方式完成所有工作,尽管有很多不必要的(虽然没有害处,除了非常小的额外开销)。
当您只传递一项任务时,调用WhenAny
毫无意义。你也可以等待任务本身;它做同样的事情。
写?? null
毫无意义。如果值为null
,请将其设为null
。它已经null
,所以你可以离开它。
您也无法将空Task
传递给FirstIfNotNullOrEmptyAsync
,而您也不应该这样做。您也可能不应该为结果生成null
IEnumerable
。如果没有项目,您应该确实有空序列。
也没有理由将该方法限制为仅适用于类序列。如果有人想要使用值类型,那么就没有理由阻止它们。
调整方法的名称也是有意义的,因此它的名称反映了它实际上在做什么。
所以现在所有这些都可以归结为:
public static async Task<T> FirstOrDefaultAsync<T>(this Task<IEnumerable<T>> task)
{
return (await task).FirstOrDefault();
}
您的其他方法也没有理由成为async
,因为除了在Task
中重新包装并返回它之外,您永远不会做任何等待值的事情。只需返回您拥有的Task
:
protected Task<T> GetSingleRecordAsync(SqlCommand SqlCommand)
{
return fetchRecordsAsync(SqlCommand, true)
.FirstOrDefaultAsync();
}