您如何实现异步操作委托方法?

Posted

技术标签:

【中文标题】您如何实现异步操作委托方法?【英文标题】:How do you implement an async action delegate method? 【发布时间】:2014-01-04 15:43:30 【问题描述】:

一些背景信息。

我正在学习 Web API 堆栈,我正在尝试以“Result”对象的形式封装所有数据,其中包含SuccessErrorCodes 等参数。

然而,不同的方法会产生不同的结果和错误代码,但结果对象通常会以相同的方式实例化。

为了节省一些时间并了解更多关于 C# 中 async/await 功能的信息,我试图将我的 Web API 操作的所有方法体包装在一个异步操作委托中,但遇到了一些问题一个障碍……

给定以下类:

public class Result

    public bool Success  get; set; 
    public List<int> ErrorCodes get; set; 


public async Task<Result> GetResultAsync()

    return await DoSomethingAsync<Result>(result =>
    
        // Do something here
        result.Success = true;
        
        if (SomethingIsTrue)
        
            result.ErrorCodes.Add(404);
            result.Success = false;
        
    

我想编写一个对Result 对象执行操作并返回它的方法。通常通过同步方法会是

public T DoSomethingAsync<T>(Action<T> resultBody) where T : Result, new()

    T result = new T();
    resultBody(result);
    return result;

但是如何使用async/await将此方法转换为异步方法?

这是我尝试过的:

public async Task<T> DoSomethingAsync<T>(Action<T, Task> resultBody) 
    where T: Result, new()

    // But I don't know what do do from here.
    // What do I await?

【问题讨论】:

如果你是new-ing up T,为什么你的方法需要异步? AFAIK 在代码中使用异步 API,您只需要从您使用的其他方法传播 asyncness。 对不起,我对此还是很陌生,你说你只需要传播是什么意思,新的 T 与它有什么关系? 我想我想通了,感谢millimoose你给了我一些思考。 您为什么还要尝试异步执行此操作?更常见的情况是,在非网络服务器的情况下,通过在任务中包装同步代码(就像您尝试做的那样)来做假异步比仅同步执行它 @AlbinAnke “传播”我的意思是 如果 你在一个方法中调用像 Stream.ReadAsync() 这样的 .NET 方法,该方法本身应该是异步的,并返回Task&lt;T&gt; 其中T 是您返回的同步方法。这个想法是,这样,您方法的每个调用者都可以“异步等待”(我不知道这是什么好词)以完成底层Stream.ReadAsync()。您可以使用的一个比喻是异步是“传染性的”,并且从低级内置 I/O 传播到其他代码,其结果取决于所述 I/O 的结果。 【参考方案1】:

async 等效于 Action&lt;T&gt;Func&lt;T, Task&gt;,所以我相信这就是您要寻找的:

public async Task<T> DoSomethingAsync<T>(Func<T, Task> resultBody)
    where T : Result, new()

  T result = new T();
  await resultBody(result);
  return result;

【讨论】:

@Stephen 显然我正在尝试在 MVVM ligth Messenger 中实现一些类似的东西,我可以用同样的方式实现吗? @JuanPabloGomez:我不熟悉他们的消息传递方式,但我不明白为什么它不起作用。 这太棒了!我认为不可能进行异步操作,并且已经将其视为语言缺陷。我没有考虑过使用 Func。谢谢。 @DFSFOT:void 方法的异步等效项是 Task-returning 方法;因此,Action 的异步等价物是Func&lt;Task&gt;Action&lt;T&gt; 的异步等价物是Func&lt;T, Task&gt;。更多信息here. @DFSFOT:当异步方法没有返回值时,它应该返回Task。如果它使用async 关键字,那么实际的Task 实例将由状态机创建,而不是直接由函数创建。【参考方案2】:

所以我相信实现这个的方法是:

public Task<T> DoSomethingAsync<T>(Action<T> resultBody) where T : Result, new()

    return Task<T>.Factory.StartNew(() =>
    
        T result = new T();
        resultBody(result);
        return result;
    );

【讨论】:

你应该避免在 ASP.NET 上使用Task.Run(更不用说StartNew)。 有什么更好的方法来做到这一点? 我发布了一个答案,并赞成@svick 的答案。他们都是很好的答案。

以上是关于您如何实现异步操作委托方法?的主要内容,如果未能解决你的问题,请参考以下文章

委托事件总结之旅

AsyncCallback

JS Async Callback

C#异步调用四大方法详解

TcpListener的BeginAcceptTcpClient方法的两个参数是啥意思

c#中断异步操作