3
votes

When calling a method like this without doing an await task, we can return the following:

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

What would be the equivalent for a IAsyncEnumerable<> and avoid the warning.

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.

2
Why is your method async if it does not use await? That's what the warning means.see sharper
Do you intend to do anything asynchronous in that method?Crowcoder
It's matching an interface. Other classes will have it async.jsgoupil
Then fine, don't pay attention to the warning.Tanveer Badar
There's no need to ignore the warnings here - the code can easily be written warning-free, as per my answer. (It's been downvoted for no obvious reason, but the other answers have been downvoted too. The code definitely works.)Jon Skeet

2 Answers

2
votes

I would probably write a synchronous iterator method, then use ToAsyncEnumerable from the System.Linq.Async package to convert it to the async version. Here's a complete example:

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;
    }
}

This complies with the interface (of using IAsyncEnumerable<T>) but allows a synchronous implementation, with no warnings. Note that the async modifier itself is not part of a method signature - it's an implementation detail. So a method specified in an interface as returning a Task<T>, IAsyncEnumerable<T> or whatever can be implemented with an async method, but doesn't have to be.

Of course for a simple example where you just want to return a single element, you could use ToAsyncEnumerable on an array, or the result of Enumerable.Repeat. For example:

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

I think you are looking for TaskCompletionSource. This gives you the most flexibility. You can set exceptions on the task, mark it incomplete etc. Alternatively 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.

Consider the following options for both, I include the first, but you can't return a Task.CompletedTask<T>, but if you just want to return a completed Task, eg cause maybe you had some out parameters that have been set, then that might be your answer.

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

or - because we can't use await without async

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

or (.Net 4.5+)

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

or the async variant of the above

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

Alternatively: (.Net 4.5+)

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

And with an IAsyncEnumerable

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

Or (.Net 4.5+)

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