I currently have some code to help execute async code on the main thread using DispatcherQueue
in a WinUI 3 application using .Net 7.
// Note that this is a simplified version of the original code, for brevity.
public static async Task Execute(this DispatcherQueue dispatcher, Func<Task> function)
{
if (dispatcher.HasThreadAccess)
{
await function();
}
else
{
var taskCompletionSource = new TaskCompletionSource<bool>();
dispatcher.TryEnqueue(ExecuteUI);
await taskCompletionSource.Task;
}
static async void ExecuteUI()
{
try
{
await function();
taskCompletionSource.SetResult(true);
}
catch (Exception e)
{
taskCompletionSource.SetException(e);
}
}
}
What would be the best way to implement this feature without using async void
?
Edit:
I understand that the DispatcherQueue.TryEnqueue
overloads take Action
or Func
parameters that are not returning Task
. My question in about about bridging that sync-to-async gap with a solution that complies with this rule.
Rule #4. Never define
async void
methods. Make the methods returnTask
instead.
- Exceptions thrown from
async void
methods always crash the process.- Callers don't even have the option to
await
the result.- Exceptions can't be reported to telemetry by the caller.
- It's impossible for your VS package to responsibly block in
Package.Close
till yourasync
work is done when it was kicked off this way.- Be cautious:
async delegate
orasync () =>
becomeasync void
methods when passed to a method that acceptsAction
delegates. Only passasync
delegates to methods that acceptFunc<Task>
orFunc<Task<T>>
parameters.
Install the CommunityToolkit.WinUI NuGet package and use one of the overloads of the
EnqueueAsync
method that accept aFunc<Task>
orFunc<Task<T>>
.The source code for these methods are available on GitHub.