LanguageExt – Как избежать двойного ожидания, когда лямбда-выражение Match является асинхронным?C#

Место общения программистов C#
Anonymous
LanguageExt – Как избежать двойного ожидания, когда лямбда-выражение Match является асинхронным?

Сообщение Anonymous »

Я использую здесь до глупости простой пример, чтобы не запутаться в деталях реального случая, а также предоставить минимально полный пример. Приведенный здесь код можно вставить в Visual Studio, Visual Studio Code или LinqPad, если вы ссылаетесь на пакет LanguageExt.Core Nuget и добавляете следующее с помощьюs...

Код: Выделить всё

using LanguageExt;
using static LanguageExt.Prelude;
Представьте, что у меня есть API, который принимает число с плавающей запятой и возвращает удвоенный квадратный корень. У меня есть следующие вспомогательные функции...

Код: Выделить всё

static Either Sqrt(double d) =>
d >= 0.0
? Math.Sqrt(d)
: "Error: Negative number";

static Either Double(double d) =>
d > 10.0
? "Error: Too big to double"
: 2 * d;
Моя конечная точка API возвращает строку вида «Результат: 23.3» в случае успеха или ошибку в противном случае.
Я связываю их вместе как следует...

Код: Выделить всё

public static string Calc(double d) =>
(from res1 in Sqrt(d)
from res2 in Double(res1)
select res2)
.Match(res => $"Result: {res}",
err => err);
Это работает так, как ожидалось. Очевидно, что мой реальный код будет содержать больше предложений from, чем этот, но я стараюсь сделать это проще.
Теперь предположим (что более реалистично) вспомогательные функции были асинхронными, то мне нужно было бы изменить свою конечную точку, чтобы она выглядела так...

Код: Выделить всё

public static async Task Calc(double d) =>
await (from res1 in Sqrt(d).ToAsync()
from res2 in Double(res1).ToAsync()
select res2)
.Match(res => $"Result: {res}",
err => err);
Опять же, все работает.

Кстати: я взял стиль кодирования, приведенный выше. прочитав часть кода Пола Лаута в выпусках LanguageExt. Если есть лучший способ сделать это, пожалуйста, предложите его. Я не претендую на звание какого-либо эксперта в этом вопросе.

Однако теперь в случае ошибок я хочу их регистрировать, отправлять электронное письмо и т. д., поэтому вторая лямбда метода Match должна быть асинхронной. Чтобы избежать ошибки компилятора, мне также нужно сначала выполнить async, а затем дождаться результата...

Код: Выделить всё

public static async Task CalcAsync2(double d) =>
await await (from res1 in Sqrt(d).ToAsync()
from res2 in Double(res1).ToAsync()
select res2)
.Match(async res => $"Result: {res}",
async err => {
// Log the error, send an email, etc (async);
return err;
});
Начинает выглядеть так, будто я делаю это совершенно неправильно. Возможно, я ошибаюсь, но ожидание ожидаемого задания кажется неправильным.
Кто-нибудь может прокомментировать здесь? Я хочу иметь возможность регистрировать ошибку, если какой-либо из вспомогательных методов возвращал Left, но предпочел бы, чтобы вся работа async (и действительно, как можно большая часть работы) выполнялась в последовательность операторов from, в результате чего лямбды в Math выполняют не более чем возвращаемые значения.

Подробнее здесь: https://stackoverflow.com/questions/786 ... a-is-async

Вернуться в «C#»