Предупреждающее сообщение в IAsyncEnumerable, когда в нем отсутствует оператор ожидания - PullRequest
2 голосов
/ 14 января 2020

При вызове такого метода без выполнения задачи await мы можем вернуть следующее:

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

Что было бы эквивалентно IAsyncEnumerable<> и избежать предупреждения.

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

Предупреждение CS1998 В этом асинхронном c методе отсутствуют операторы «ожидания» и он будет работать синхронно. Попробуйте использовать оператор 'await' для ожидания неблокирующих вызовов API или 'await Task.Run (...)' для выполнения работы с процессором в фоновом потоке.

Ответы [ 2 ]

1 голос
/ 14 января 2020

Я бы, вероятно, написал синхронный метод итератора , а затем использовал бы ToAsyncEnumerable из пакета System.Linq.Async для преобразования его в версию asyn c. Вот полный пример:

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 является , а не частью сигнатуры метода - это деталь реализации. Таким образом, метод, указанный в интерфейсе как возвращающий Task<T>, IAsyncEnumerable<T> или любой другой, может быть реализован с помощью asyn c метода, но это не обязательно.

Конечно, для простого примера где вы просто хотите вернуть один элемент, вы можете использовать ToAsyncEnumerable для массива или результат Enumerable.Repeat. Например:

static IAsyncEnumerable<bool> GetBoolsAsync() =>
    new[] { true }.ToAsyncEnumerable();
1 голос
/ 14 января 2020

Я думаю, что вы ищете TaskCompletionSource. Это дает вам наибольшую гибкость. Вы можете установить исключения для задачи, отметить ее как незавершенную и т. Д. c. В качестве альтернативы Task.FromResult.

Во многих сценариях ios полезно включить Задачу для представления внешней асинхронной операции. TaskCompletionSource предоставляется для этой цели. Это позволяет создавать задачи, которые могут быть переданы потребителям. Потребители могут использовать члены задачи так же, как и в любом другом сценарии обработки переменных членов задачи.

Рассмотрим следующие варианты для обоих, я включаю первый, но вы не можете вернуть Task.CompletedTask<T>, но если вы просто хотите вернуть выполненное задание, например, потому что, возможно, у вас были установлены некоторые параметры out, тогда это может быть ваш ответ.

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

или - потому что мы не можем использовать await без asyn c

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

или асин c варианта выше

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