#c# #async-await #task #extension-methods
#c# #async-await #задача #расширение-методы
Вопрос:
Я пытаюсь создать .WithDelay(seconds);
метод, который я могу добавить в конце вызовов асинхронных методов.
Проблема, с которой я сталкиваюсь, заключается в том, что сначала вызывается асинхронный метод, затем происходит задержка, я хочу, чтобы все было наоборот, без переключения порядка вызова.
Например, я хочу, await MyMethod().WithDelay(seconds);
а не await WithDelay(seconds).MyMethod();
.
Вот что у меня есть на данный момент, сначала он вызывает метод:
public async static Task<T> WithDelay<T>(this Task<T> task, int delay) {
await Task.Delay(delay);
return await task;
}
Я ожидаю, что сначала произойдет задержка, а затем будет запущен сам метод.
Ответ №1:
Я хочу, чтобы было наоборот, без переключения порядка вызова.
Это невозможно, потому что язык C # поддерживает методы расширения только для типов, а не для методов.
Ближайший, который вы можете получить, — это метод расширения для делегатов:
public static async Task<T> WithDelay<T>(this Func<Task<T>> func, int delay) {
await Task.Delay(delay);
return await func();
}
Использование по-прежнему оказывается неудобным:
// Either:
Func<Task<MyType>> func = MyMethod;
var result = await func.WithDelay(1000);
// or (assuming "using static"):
var result = await WithDelay(MyMethod, 1000);
// What you really want, not currently possible:
// var result = await MyMethod.WithDelay(1000);
В подобных ситуациях, связанных с типом, это может помочь сначала решить проблему синхронно, а затем преобразовать это решение в async
. Если язык препятствует хорошему синхронному решению, то он, скорее всего, будет препятствовать хорошему асинхронному решению.
Есть предложение по методам расширения в methods, но сегодня это не является частью языка.
Комментарии:
1. Не тот ответ, который я искал, но спасибо. Я прекращу поиски.
Ответ №2:
Сработает ли приведенное ниже?
public static Task Async<T>(this T o, Action<T> action, CancellationToken token = default) {
if (token.IsCancellationRequested) {
return Task.FromCanceled(token);
}
try {
action(o);
return Task.CompletedTask;
} catch (Exception e) {
return Task.FromException(e);
}
}
Пример:
public static Task CommitAsync(this IDbTransaction transaction, CancellationToken token = default)
=> transaction.Async(x=> transaction.Commit(), token);