IAsyncEnumerable 缺少 await 运算符时的警告消息

Warning message in IAsyncEnumerable when it lacks the await operator

在不执行 await 任务的情况下调用这样的方法时,我们可以 return 以下操作:

public Task<bool> GetBoolAsync()
{
    return Task.FromResult(true);
}

什么是 IAsyncEnumerable<> 的等价物并避免警告。

async IAsyncEnumerable<bool> GetBoolsAsync() // <- Ugly warning
{
    yield return true;
    yield break;
}

Warning CS1998 This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

我认为您正在寻找 TaskCompletionSource。这为您提供了最大的灵活性。您可以在任务上设置例外,将其标记为未完成等。或者 Task.FromResult.

In many scenarios, it is useful to enable a Task to represent an external asynchronous operation. TaskCompletionSource is provided for this purpose. It enables the creation of a task that can be handed out to consumers. The consumers can use the members of the task the same way as they would in any other scenario handling task member variables.

考虑以下两个选项,我包括第一个,但你不能return一个Task.CompletedTask<T>,但如果你只想return一个已完成的任务,例如因为也许您已经设置了一些 out 参数,那么这可能就是您的答案。

    static async Task SomeMethod()
    {
        await Task.CompletedTask;
    }

或者 - 因为我们不能在没有 async 的情况下使用 await

    static Task<bool> SomeOtherMethod()
    {
        var taskSource = new TaskCompletionSource<bool>();
        taskSource.SetResult(true);
        return taskSource.Task;
    }

或(.Net 4.5+)

   static Task<bool> SomeEvenOtherMethod()
    {
        return Task.FromResult(true);
    }

或上述的异步变体

    static async Task<bool> SomeEvenOtherMethod()
    {
        var taskSource = new TaskCompletionSource<bool>();
        taskSource.SetResult(true);
        return (await taskSource.Task);
    }

或者:(.Net 4.5+)

    static async Task<bool> SomeEvenOtherMethod()
    {
        return(await Task.FromResult(true));
    }

并使用 IAsyncEnumerable

    static async IAsyncEnumerable<bool> GetBoolsAsync()
    {
        var t = await SomeOtherMethod();
        yield return t;
    }

或(.Net 4.5+)

    static async IAsyncEnumerable<bool> GetBoolsAsync() 
    {
        yield return await Task.FromResult(true);
    }

我可能会编写一个 同步 迭代器方法,然后使用 System.Linq.Async 包中的 ToAsyncEnumerable 将其转换为异步版本。这是一个完整的例子:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

class Program
{
    static async Task Main(string[] args)
    {
        await foreach (bool x in GetBoolsAsync())
        {
            Console.WriteLine(x);
        }
    }

    // Method to return an IAsyncEnumerable<T>. It doesn't
    // need the async modifier.
    static IAsyncEnumerable<bool> GetBoolsAsync() =>
        GetBools().ToAsyncEnumerable();

    // Regular synchronous iterator method.
    static IEnumerable<bool> GetBools()
    {
        yield return true;
        yield break;
    }
}

这符合接口(使用 IAsyncEnumerable<T>)但允许同步实现,没有警告。请注意,async 修饰符本身是方法签名的 而不是 的一部分——它是一个实现细节。因此,在接口中指定为 returning a Task<T>IAsyncEnumerable<T> 或任何可以使用异步方法实现的方法,但不一定是。

当然,对于您只想 return 单个元素的简单示例,您可以在数组上使用 ToAsyncEnumerable,或者 Enumerable.Repeat 的结果。例如:

static IAsyncEnumerable<bool> GetBoolsAsync() =>
    new[] { true }.ToAsyncEnumerable();