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


132

一点背景资料。

我正在学习Web API堆栈,并且正在尝试以带有诸如Success和ErrorCodes之类的参数的“结果”对象的形式封装所有数据。

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

为了节省时间并进一步了解C#中的异步/等待功能,我试图将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?
}

1
如果您正在new启动T,为什么您的方法需要异步?使用异步API的代码中的AFAIK ,您只需传播所async使用的其他方法的本质即可。
millimoose

抱歉,我对此还不是很陌生,当您说只需要传播时,您是什么意思?对T进行新的处理与它有什么关系?
Albin Anke

我想我已经解决了,谢谢毫微微,您给了我一些思考。
Albin Anke 2013年

1
您为什么还要尝试异步执行此操作?在非Web服务器情况下,通常通过将同步代码包装在任务中(例如您尝试执行的操作)来进行虚假异步操作,比仅同步进行操作要
Scott Chamberlain

1
@AlbinAnke通过“传播”我的意思是,如果你调用像.NET方法Stream.ReadAsync()中的方法,该方法本身应该是异步的,并返回一个Task<T>地方T是你不得不返回了该方法的同步。想法是这样,您的方法的每个调用者都可以随后“异步等待”(我不知道这是什么好术语)Stream.ReadAsync()来完成基础。可以使用的一个比喻是,异步是“传染性的”,并且从底层的内置I / O传播到其他代码,这些代码的结果取决于所述I / O的结果。
millimoose

Answers:


307

async当量Action<T>Func<T, Task>,所以我相信这是你要找的内容:

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中,我可以实现相同的方式吗?
Juan Pablo Gomez 2015年

@JuanPabloGomez:我不熟悉他们的消息传递方式,但我不明白为什么它不起作用。
Stephen Cleary

1
这真太了不起了!我认为不可能进行异步操作,并且已经将其视为语言缺陷。我没有考虑使用Func。谢谢。
Noel Widmer

2
@DFSFOT:方法的异步等效项voidTask-returning方法;因此,Actionis Func<Task>的异步等效项,Action<T>is 的异步等效项Func<T, Task>。更多信息在这里
Stephen Cleary

1
@DFSFOT:异步方法Task没有返回值时应返回。如果使用async关键字,则实际Task实例将由状态机而非函数直接创建。
Stephen Cleary

-11

因此,我相信实现此目标的方法是:

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

7
您应该避免Task.Run(甚至更多StartNew)在ASP.NET上。
Stephen Cleary 2013年

有什么更好的方法可以做到这一点?
Albin Anke 2013年

我发布了答案,并也对@svick的答案进行了投票。他们都是很好的答案。
Stephen Cleary 2013年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.