这真的是异步吗? IEnumerable <t>扩展

时间:2016-11-07 18:50:45

标签: c# asynchronous collections

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的异步扩展的正确方法,还是会进行同步?

我真的需要创建另一个任务(第一个)吗?

2 个答案:

答案 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();
}