一行即发即忘:void 与 async void + await
One line fire and forget: void vs. async void + await
我有一个 void
事件处理程序,它只包含一行调用 await
able 方法。
void Handler( object sender, EventArgs args ) => AwaitableMethod();
将 return 类型更改为 Task
不是一种选择,因此无论语法糖如何,它都是即发即弃。即便如此,Visual Studio 在未 await
ed 调用下方放置了一个绿色波浪线,建议我将处理程序 async void
和 await
调用。
async void Handler( object sender, EventArgs args ) => await AwaitableMethod();
我的理解是在这种情况下添加 async void
和 await
只是无用的开销。 Visual Studio 是否知道一些我不知道的事情,还是只是不必要地烦人?
在这种特殊情况下,这主要取决于您的错误处理。
如果AwaitableMethod
异步抛出,会在第二个版本的UI线程上抛出。
My understanding is that adding async void and await in this case would just be useless overhead.
没有
如果Handler
return编辑了一个Task
,那就是真的,eliding async
/await
就可以了;没有 async
/await
的代码只会 return 直接 Task
而不是 "unwrapping" 它与 await
和 "wrapping" 它返回变成 Task
和 async
.
然而,这里不是这种情况; Handler
returns void
,所以没有 async
/await
的代码将忽略 returned Task
,这是绝大多数时候都是错误的(因此编译器警告)。具体来说,忽略 Task
将忽略来自 Task
的任何异常。您的代码也无法知道被忽略的 Task
何时完成,但大概这是可以接受的,因为您的处理程序正在 returning void
.
async void
方法执行了 "registration" 以便框架知道有一项任务仍在进行中,因此框架知道何时可以安全关闭。 .NET 提供的唯一真正关心的框架是 ASP.NET pre-Core;所有其他 .NET 提供的框架(包括所有 UI 框架)忽略 "registration".
我建议在这种情况下避免使用事件处理程序,并尽可能使用类似这样的东西。
public class Eventful
{
private readonly List<Func<Task>> _handlers = new List<Func<Task>>();
public void AddHandler(Func<Task> handler) => _handlers.Add(handler);
private async Task RunHandlers()
{
foreach (var handler in _handlers)
{
await handler();
}
}
}
public class Consumer
{
public Consumer()
{
var eventful = new Eventful();
eventful.AddHandler(async () =>
{
await DoAsyncTask();
});
}
private static async Task DoAsyncTask()
{
await Task.CompletedTask;
}
}
我有一个 void
事件处理程序,它只包含一行调用 await
able 方法。
void Handler( object sender, EventArgs args ) => AwaitableMethod();
将 return 类型更改为 Task
不是一种选择,因此无论语法糖如何,它都是即发即弃。即便如此,Visual Studio 在未 await
ed 调用下方放置了一个绿色波浪线,建议我将处理程序 async void
和 await
调用。
async void Handler( object sender, EventArgs args ) => await AwaitableMethod();
我的理解是在这种情况下添加 async void
和 await
只是无用的开销。 Visual Studio 是否知道一些我不知道的事情,还是只是不必要地烦人?
在这种特殊情况下,这主要取决于您的错误处理。
如果AwaitableMethod
异步抛出,会在第二个版本的UI线程上抛出。
My understanding is that adding async void and await in this case would just be useless overhead.
没有
如果Handler
return编辑了一个Task
,那就是真的,eliding async
/await
就可以了;没有 async
/await
的代码只会 return 直接 Task
而不是 "unwrapping" 它与 await
和 "wrapping" 它返回变成 Task
和 async
.
然而,这里不是这种情况; Handler
returns void
,所以没有 async
/await
的代码将忽略 returned Task
,这是绝大多数时候都是错误的(因此编译器警告)。具体来说,忽略 Task
将忽略来自 Task
的任何异常。您的代码也无法知道被忽略的 Task
何时完成,但大概这是可以接受的,因为您的处理程序正在 returning void
.
async void
方法执行了 "registration" 以便框架知道有一项任务仍在进行中,因此框架知道何时可以安全关闭。 .NET 提供的唯一真正关心的框架是 ASP.NET pre-Core;所有其他 .NET 提供的框架(包括所有 UI 框架)忽略 "registration".
我建议在这种情况下避免使用事件处理程序,并尽可能使用类似这样的东西。
public class Eventful
{
private readonly List<Func<Task>> _handlers = new List<Func<Task>>();
public void AddHandler(Func<Task> handler) => _handlers.Add(handler);
private async Task RunHandlers()
{
foreach (var handler in _handlers)
{
await handler();
}
}
}
public class Consumer
{
public Consumer()
{
var eventful = new Eventful();
eventful.AddHandler(async () =>
{
await DoAsyncTask();
});
}
private static async Task DoAsyncTask()
{
await Task.CompletedTask;
}
}