简化异步调用






3.78/5 (9投票s)
如何减少调用异步方法的开销和复杂性。
引言
我经常会回顾旧代码,看看我是如何实现异步调用的。
不止一次,我想到可以将 async
“内容”封装起来,这样我就不需要记住如何实现了。
本文介绍的是如何将 async
调用封装成更容易记忆的东西。
典型的异步用法
这个例子展示了我通常如何实现一个异步调用。
public void Backup()
{
backupInProgress = true;
Task<String> backup = BackupAsync();
backup.GetAwaiter().OnCompleted(
() =>
{
BackupStatus = backup.Result;
backupInProgress = false;
});
}
其中 BackupAsync 处理异步和 await
private async Task<String> BackupAsync()
{
Func<string> a = () =>
{
// Do stuff here
};
return await Task.Run(a);
}
我通常使用 Function
/Task
的 Result
来更新逻辑或 UI,当异步方法完成时。 在上面的例子中,设置了一个属性 BackupStatus
。
减少代码
异步调用可以封装到以下方法中: public static void Do(Func<T> func, Action<T> completed)
{
Task<T> task = AsyncTask(func);
task.GetAwaiter().OnCompleted(() =>
{
if (!task.IsFaulted) // Check if Faulted
completed(task.Result);
});
}
其中 AsyncTask 定义如下
private static async Task<T> AsyncTask(Func<T> func)
{
return await Task.Run(func);
}
现在我可以异步调用一个函数 (func
),并将结果传递给一个 Action (completed)
,使用以下代码
Async<string>.Do(Backup, UpdateUI);
其中 Backup 和 UpdateUI 是常规方法,以异步方式调用:
private string Backup()
{
// Do backup
return "Done"; // return status
}
private void UpdateUI(string status)
{
BackupStatus = status;
}
完美!不再需要 async await,但是我们如何处理异常呢?
嗯,我们可以创建一个重载,如果 Task
具有 IsFaulted
设置,则调用另一个方法
public static void Do(Func<T> func, Action<T> completed, Action<Exception> failure) { Task<T> task = AsyncTask(func); task.GetAwaiter().OnCompleted(() => { if (task.IsFaulted) failure(task.Exception); else completed.Invoke(task.Result); }); }这样我们就可以像这样调用 Do 方法
Async<string>.Do(Backup, UpdateUI, HandleException);
其中 HandleException:
private void HandleException(Exception parameter) { // Handle exception }
请查看提供的示例以获取更多信息。
历史
我最初的想法。