您如何实现异步操作委托方法?
Posted
技术标签:
【中文标题】您如何实现异步操作委托方法?【英文标题】:How do you implement an async action delegate method? 【发布时间】:2014-01-04 15:43:30 【问题描述】:一些背景信息。
我正在学习 Web API 堆栈,我正在尝试以“Result
”对象的形式封装所有数据,其中包含Success
和ErrorCodes
等参数。
然而,不同的方法会产生不同的结果和错误代码,但结果对象通常会以相同的方式实例化。
为了节省一些时间并了解更多关于 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,您只需要从您使用的其他方法传播 async
ness。
对不起,我对此还是很陌生,你说你只需要传播是什么意思,新的 T 与它有什么关系?
我想我想通了,感谢millimoose你给了我一些思考。
您为什么还要尝试异步执行此操作?更常见的情况是,在非网络服务器的情况下,通过在任务中包装同步代码(就像您尝试做的那样)来做假异步比仅同步执行它慢。
@AlbinAnke “传播”我的意思是 如果 你在一个方法中调用像 Stream.ReadAsync()
这样的 .NET 方法,该方法本身应该是异步的,并返回Task<T>
其中T
是您返回的同步方法。这个想法是,这样,您方法的每个调用者都可以“异步等待”(我不知道这是什么好词)以完成底层Stream.ReadAsync()
。您可以使用的一个比喻是异步是“传染性的”,并且从低级内置 I/O 传播到其他代码,其结果取决于所述 I/O 的结果。
【参考方案1】:
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 中实现一些类似的东西,我可以用同样的方式实现吗? @JuanPabloGomez:我不熟悉他们的消息传递方式,但我不明白为什么它不起作用。 这太棒了!我认为不可能进行异步操作,并且已经将其视为语言缺陷。我没有考虑过使用 Func。谢谢。 @DFSFOT:void
方法的异步等效项是 Task
-returning 方法;因此,Action
的异步等价物是Func<Task>
,Action<T>
的异步等价物是Func<T, Task>
。更多信息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 的答案。他们都是很好的答案。以上是关于您如何实现异步操作委托方法?的主要内容,如果未能解决你的问题,请参考以下文章