如何为异步方法创建通用扩展方法?

How to create a generic extension method for async methods?

我正在尝试创建一个 .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;
}

我希望延迟先发生,然后才是实际方法 运行。

I want it the other way around, without switching the order of the call.

这是不可能的,因为 C# 语言只支持 types 的扩展方法,不支持 methods.

最接近的是委托的扩展方法:

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。如果语言阻止了良好的同步解决方案,那么它很可能会阻止良好的异步解决方案。

方法上有一个 proposal 扩展方法,但它不是今天语言的一部分。

下面行不行?

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