所以我理解为什么从异步中返回void通常没有任何意义,但我遇到了一种我认为完全有效的情况。考虑以下设计的例子:
protected override void OnLoad(EventArgs e)
{
if (CustomTask == null)
// Do not await anything, let OnLoad return.
PrimeCustomTask();
}
private TaskCompletionSource<int> CustomTask;
// I DO NOT care about the return value from this. So why is void bad?
private async void PrimeCustomTask()
{
CustomTask = new TaskCompletionSource<int>();
int result = 0;
try
{
// Wait for button click to set the value, but do not block the UI.
result = await CustomTask.Task;
}
catch
{
// Handle exceptions
}
CustomTask = null;
// Show the value
MessageBox.Show(result.ToString());
}
private void button1_Click(object sender, EventArgs e)
{
if (CustomTask != null)
CustomTask.SetResult(500);
}
我意识到这是一个不寻常的例子,但我试图让它更简单,更通用。有人可以向我解释为什么这是可怕的代码,以及我如何修改它以正确遵循惯例?
感谢您的帮助。
答案 0 :(得分:15)
嗯,详细介绍"avoid async void
" article中的原因:
PrimeCustomTask
的例外将非常难以处理。PrimeCustomTask
中的逻辑就在那里,就是它 - 它不能被组合成更高级别的async
方法。PrimeCustomTask
的单元测试(或任何调用它的单元测试)。同样重要的是要注意async Task
是自然的方法。在several languages that have adopted async
/await
中,C#/ VB是唯一支持async void
的AFAIK。 F#没有,Python没有,JavaScript和TypeScript没有。从语言设计的角度来看,async void
是不自然的。
将async void
添加到C#/ VB的原因是启用异步事件处理程序。如果您更改代码以使用async void
事件处理程序:
protected override async void OnLoad(EventArgs e)
{
if (CustomTask == null)
await PrimeCustomTask();
}
private async Task PrimeCustomTask()
然后async void
的缺点仅限于您的事件处理程序。特别是,来自PrimeCustomTask
的异常自然地传播到其(异步)调用者(OnLoad
),PrimeCustomTask
可以组成(从其他异步方法自然调用),PrimeCustomTask
在单元测试中更容易包含。
答案 1 :(得分:7)
使用void async只是通常被视为“坏”,因为:
有很多案例(比如你的)使用它很好。使用时要小心。