Есть ли метод, эквивалентный ключевому слову async? - PullRequest
0 голосов
/ 24 октября 2018

Иногда я хочу что-то сделать с результатом асинхронного метода, например:

var foos = (await GetObjectAsync<IEnumerable<Foo>>()).ToList();

Но это обозначение трудно читаемо из-за скобок.Если я вызову другой асинхронный метод с результатом, вложенные множественные await выражения, например:

var result = (await (await GetObjectAsync<IEnumerable<Foo>>()).First().SomeMethodAsync()).GetResult();

Я хотел бы написать более беглый эквивалент, например:

var foos = GetObjectAsync<IEnumerable<Foo>>()
    .Async()
    .First()
    .SomeMethodAsync()
    .Async()
    .GetResult();

Я прочитал документацию , но единственное, что имеет правильную подпись (если я что-то пропустил), это Result, а Result не то, что я хочу, потому что это не эквивалент await.

Существует ли такой метод?Могу ли я создать расширение для этого, если оно не существует?

Ответы [ 3 ]

0 голосов
/ 24 октября 2018

Вы ищете ContinueWith:

await GetObjectAsync<IEnumerable<Foo>>()
    .ContinueWith(task => task.Result.ToList());

Но это будет работать хуже и имеет некоторые сложности, которые могут занять некоторое время, чтобы понять, например, убедитесь, что вы используете правильный планировщик для вашегокод продолжения (await делает это за вас).

Я бы предпочел вместо этого просто разбить ваш код на несколько строк, если читаемость является проблемой:

var foosEnumerable = await GetObjectAsync<IEnumerable<Foo>>();
var foos = foosEnumerable.ToList();
0 голосов
/ 24 октября 2018

Чтобы получить свободный синтаксис, вы можете создать функтор и монаду из Task<T> с помощью следующих методов расширения:

public static async Task<TResult> Map<T, TResult>(this Task<T> source, Func<T, TResult> func)
{
    var result = await source.ConfigureAwait(false);

    return func(result);
}

public static async Task<TResult> Bind<T, TResult>(this Task<T> source, Func<T, Task<TResult>> func)
{
    var result = await source.ConfigureAwait(false);

    return await func(result).ConfigureAwait(false);
}

Это позволяет вам писать свой код в виде цепочки методов:

var resultTask = GetObjectAsync<IEnumerable<Foo>>()
    .Map(foos => foos.First())
    .Bind(foo => foo.SomeMethodAsync())
    .Map(r => r.GetResult());

Конечно, я не рассматриваю производительность здесь, но для не критичной к производительности части кода я предпочитаю удобочитаемость микрооптимизациям, если это помогает сделать ваш код более понятным (в некоторых областях я нахожу несколько случаев, когдаэтот синтаксис помогает).

Также имейте в виду, что очевидно, что вы все еще получаете задание обратно, так что в какой-то момент вам придется либо ждать его, либо блокировать с помощью Result или Wait.

Объединение методов также может быть достигнуто с помощью ContinueWith, как в ответе @Cory Nelson (тщательно используя правильные аргументы для планировщика и параметров), избегая создания асинхронного конечного автомата, но для простоты я использовал async и await в расширенияхчто совершенно безопасно.

Кроме того, если вы переименуете Map в Select и Bind to SelectMany (aи добавьте перегрузку с проекцией), вы также можете использовать синтаксис запросов LINQ для задач, хотя это, вероятно, вас не заинтересует, поскольку вы специально пытаетесь отойти от этого синтаксиса от того, что я могу прочитать.

0 голосов
/ 24 октября 2018

Вы можете использовать

var foos = GetObjectAsync<IEnumberable<Foo>>().GetAwaiter().GetResult().ToList()

, но это не то же самое!если вы используете ключевое слово «await», то во время ожидания результата Windows Messageloop обрабатывается, а ваше приложение не замораживается (поэтому обрабатываются события мыши и т. д.).Если вы используете «GetAwaiter (). GetResult» или «.Wait ()», то поток блокируется во время ожидания.

Таким образом, для «await» нет эквивалента.Но есть другой синтаксис, который выглядит аналогично, но ведет себя совершенно иначе.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...