C# 区分作废和任务返回方法

C# 区分作废和任务返回方法,c#,async-await,C#,Async Await,我正在处理一个类,它有一个带有Action参数的方法: public void RegisterCallback<T> (Action<T> callback); 其中AsyncCallback是 private Task AsyncCallback(string s) { return Task.Delay(0); } 天真的方法是采用如下方法: void RegisterCallback<T>(Func<T

我正在处理一个类,它有一个带有
Action
参数的方法:

public void RegisterCallback<T> (Action<T> callback);
其中
AsyncCallback

    private Task AsyncCallback(string s)
    {
        return Task.Delay(0);
    }
天真的方法是采用如下方法:

void RegisterCallback<T>(Func<T, Type> callback);
void RegisterCallback(Func回调);
但它也有一些问题:

//1
instance.RegisterCallback<string>(async t => await Task.Delay(0));
//2
instance.RegisterCallback<string>(AsyncCallback); //method group with async
//1
RegisterCallback(异步t=>wait Task.Delay(0));
//2
RegisterCallback(异步回调)//具有异步的方法组
第一个被解析为
操作回调
重载,第二个由于调用不明确而无法编译

好吧,我对这个界面很满意:

 void RegisterAsyncCallback<T>(Func<T, Task> callback);   
void RegisterAsyncCallback(Func回调);
但是,编译这两个调用时没有问题:

   instance.RegisterCallback<string>(async t => await Task.Delay(0));
   instance.RegisterAsyncCallback<string>(async t => await Task.Delay(0));
instance.RegisterCallback(异步t=>wait Task.Delay(0));
RegisterAsyncCallback(异步t=>wait Task.Delay(0));
有没有一种方法可以设计这个公共api,这样用户只会对一个方法使用
void
回调,而对另一个方法使用任务返回

也许有人能给我指出解决类似问题的现有api

可以找到完整的代码

有没有一种方法可以设计这个公共api,让用户只对一个方法使用void回调,而对另一个方法使用任务返回

不,不是真的。问题是
操作
代表。正如您已经发现的那样,它允许使用大量不同的lambda表达式。
注册表回调(操作回调)
遇到的一个主要问题是,如果有人这样使用它:

instance.RegisterCallback<string>(async _ => await Task.Delay(0));
instance.RegisterCallback(异步=>wait Task.Delay(0));

他们正在创建一个
异步void
,这是一个巨大的问题。您对
Func
的想法是正确的。另外,我喜欢您重命名函数并添加“Async”的想法,这似乎是合适的,
RegisterAsyncCallback(Func callback)

这里没有好的解决方案;您要么会遇到方法重载的不明确调用错误,要么会有一个全新的API

就我个人而言,我会添加
Func
重载,并接受突破性的更改,不再允许方法重载。或者,您可以在新方法(
RegisterCallbackEx
?)上创建两个重载,并将旧方法标记为
过时的
——这将允许编译旧代码,但鼓励开发人员更改调用

也许有人能给我指出解决类似问题的现有api

好吧,我可以给你举个例子,类似的问题没有解决

Task.Factory.StartNew
通常用于将工作排队到线程池。它基于
操作
,我相信它与方法组一起工作

当.NET团队想要添加异步支持时,他们引入了一个新的API:
Task.Run
,它对于
Action
Func
是重载的

(请注意,在这种情况下,
Task.Run
在技术上仅支持
StartNew
使用的一个子集,并且
StartNew
未标记为
已过时

他们考虑了自己的选择,但这是他们能想到的最好的办法。请注意,以下问题仍然存在,开发人员在这里定期询问这两个问题:

  • Task.Run
    不支持方法组
  • StartNew
    将使用
    async
    lambdas很好地编译,但会以令人惊讶的方式运行(由于
    async void

由于他们正在更改.NET BCL,向后兼容性至关重要。对于个人库,我更喜欢更安全/更干净的API,而不是严格的向后兼容性,因此我会在您的情况下做出另一个选择(即,只需添加一个
Func
重载作为主要版本升级的一部分)。

这是非常正确的-我忘记了
async void
可以转换为
Action
。据我所知,没有办法编写一个明确禁止异步/非异步委托参数的方法。我不确定您想了解有关实现的哪些信息?它只是一个回调(值)。我需要异步重载中更复杂的错误处理。用更多代码更新你的fiddle,我会再看一看。我看到的问题是
Action
将始终接受
RegisterCallback(异步=>wait Task.Delay(0))。所以没有办法区分。这现在更有意义了,最初您没有提供
IMyInterface
实际上是
IMyInterface
。正如我所说(Steve Cleary也同意),添加
Func
,并充分利用它。感谢Task.Run提供的好例子。我在找类似的东西。
   instance.RegisterCallback<string>(async t => await Task.Delay(0));
   instance.RegisterAsyncCallback<string>(async t => await Task.Delay(0));
instance.RegisterCallback<string>(async _ => await Task.Delay(0));