Search code examples
.net-coremaui

Dispatcher.DispatchAsync() vs Dispatcher.Dispatch() for .NET Maui


Dispatcher.DispatchAsync() and Dispatcher.Dispatch() are "new" constructs in .NET Core as of .NET 8, the former being an extension of the latter. I'm trying to understand these two things. Almost all the search results I can find do not apply to Maui, except the documentation, and the source code, though many results appear similar. The problem being that while I understand that the async method returns a Task, and the other one returns a bool, I'm unsure of the overall behavior beyond that.

One of the issues that I have is that in the code below, OnFormFieldChanged() returns a Task. When I use the first item below, ReSharper warns me: "Avoid using 'async' lambda when delegate type returns 'void'". This is the one that my boss prefers. The second one seems better to me (ReSharper certainly doesn't complain), but my boss is giving me static about the second one (as in, "don't do that!"), which I don't completely get. Unfortunately, his explanations don't make sense to me, so I'm asking here. It may be important to note that he's developed apps using WPF before, whereas I haven't.

Dispatcher.Dispatch(async () =>
{
            IsModified = true;
            await OnFormFieldChanged();
});

Dispatcher.DispatchAsync(async () =>
{
            IsModified = true;
            await OnFormFieldChanged();
});

So - what is the difference in behavior in .NET Maui between the two code snippets shown?

PS This isn't about "async void" at all. My boss has made it clear that the behavior between these two snippets is different, but I can't see how.


Solution

  • It's actually really simple. Both are intended to be called from a worker thread to schedule work to be done on the UI thread. Neither will block the calling thread.

    Dispatch is not awaitable. It is strictly a fire-and-forget; it will return immediately, almost certainly before the scheduled work is complete.

    The DispatchAsync overloads are all actually extension methods, and all they do is inject a TaskCompletionSource between themselves and your delegate, and return the Task so that you can await the completion of the UI work (or get a return value) on your worker thread. See code here.

    So DispatchAsync is awaitable, and Dispatch is fire and forget.

    Note however, in your specific example, if you don't await the DispatchAsync call, the behavior will be equivalent to Dispatch.