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

时间:2019-04-09 13:59:30

标签: c# async-await task extension-methods

我正在尝试创建一个#include <stdio.h> #include <string.h> #include <stdlib.h> char** scan(FILE *fin, int *n); void sort(char **array, int n); void print(FILE *fout, char **array, int n); int main(int argc, char *argv[]) { FILE *fp,*dat; int n; char **niz; fp=fopen(argv[1],"r"); dat=fopen(argv[2],"w"); niz=scan(fp,&n); printf("%d", n); sort(niz,n); print(dat,niz,n); fclose(fp); fclose(dat); free(niz); { char** scan(FILE *fp, int *n) { int c,m=0,g=0; char **niz; niz=(char**)calloc(1,sizeof(char *)); niz[0]=(char*)calloc(21,sizeof(char)); while((c=fgetc(fp)!=EOF)) { if((c>64 && c<91) || (c>96 && c<123)) niz[m][g++]=c; else if(niz[m][0]!=0) { m++; g=0; niz=(char**)realloc(niz,(m+1)*sizeof(*char)); niz[m]=(char*)calloc(21,sizeof(char)); } } if(niz[m][0]==0) *n=m; else *n=m-1; return niz; } 方法,可以在异步方法调用的末尾添加该方法。

我得到的问题是先调用async方法,然后再发生延迟,我希望在不改变调用顺序的情况下反之。

例如,我想要.WithDelay(seconds);而不是await MyMethod().WithDelay(seconds);

这是我到目前为止所拥有的,它首先调用该方法:

await WithDelay(seconds).MyMethod();

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

2 个答案:

答案 0 :(得分:4)

  

我希望反过来,而无需切换呼叫顺序。

这是不可能的,因为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。如果该语言阻止了一个好的同步解决方案,那么它很可能会阻止一个好的异步解决方案。

方法的扩展方法有一个proposal,但今天它已不在语言中。

答案 1 :(得分:-1)

下面能用吗?

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