What is the difference between `async void` (no wait) vs` void`

Adapted from an article on Asynchronous Waiting by Stephen Cleary:

Figure 2 Exceptions to the Cant Be Caught with Catch Asynchronous Invalidity Method

private async void ThrowExceptionAsync()
{
  throw new InvalidOperationException();
}
public void AsyncVoidExceptions_CannotBeCaughtByCatch()
{
  try
  {
    ThrowExceptionAsync();
  }
  catch (Exception)
  {
    // The exception is never caught here!
    throw;
  }
}

... any exceptions excluded from the async void method will be created directly in the SynchronizationContext that was active when the async void method was run ...

What does it mean? I wrote an extended example to try to gather more information. It has the same behavior as in Figure 2:

static void Main()
{

    AppDomain.CurrentDomain.UnhandledException += (sender, ex) => 
    {
        LogCurrentSynchronizationContext("AppDomain.CurrentDomain.UnhandledException");
        LogException("AppDomain.CurrentDomain.UnhandledException", ex.ExceptionObject as Exception);
    };

    try
    {
        try
        {
            void ThrowExceptionVoid() => throw new Exception("ThrowExceptionVoid");

            ThrowExceptionVoid();
        }
        catch (Exception ex)
        {
            LogException("AsyncMain - Catch - ThrowExceptionVoid", ex);
        }

        try
        {
            // CS1998 C# This async method lacks 'await' operators and will run synchronously. 
            async void ThrowExceptionAsyncVoid() => throw new Exception("ThrowExceptionAsyncVoid");

            ThrowExceptionAsyncVoid();
        }
        // exception cannot be caught, despite the code running synchronously.
        catch (Exception ex) 
        {
            LogException("AsyncMain - Catch - ThrowExceptionAsyncVoid", ex);
        }
    }
    catch (Exception ex)
    {
        LogException("Main", ex);
    }

    Console.ReadKey();
}

private static void LogCurrentSynchronizationContext(string prefix)
    => Debug.WriteLine($"{prefix} - " +
        $"CurrentSynchronizationContext: {SynchronizationContext.Current?.GetType().Name} " +
        $"- {SynchronizationContext.Current?.GetHashCode()}");

private static void LogException(string prefix, Exception ex)
    => Debug.WriteLine($"{prefix} - Exception - {ex.Message}");

Debug output:

Exception thrown: 'System.Exception' in ConsoleApp3.dll
AsyncMain - Catch - ThrowExceptionVoid - Exception - ThrowExceptionVoid
Exception thrown: 'System.Exception' in ConsoleApp3.dll
An exception of type 'System.Exception' occurred in ConsoleApp3.dll but was not handled in user code
ThrowExceptionAsyncVoid
AppDomain.CurrentDomain.UnhandledException - CurrentSynchronizationContext:  - 
AppDomain.CurrentDomain.UnhandledException - Exception - ThrowExceptionAsyncVoid
The thread 0x1c70 has exited with code 0 (0x0).
An unhandled exception of type 'System.Exception' occurred in System.Private.CoreLib.ni.dll
ThrowExceptionAsyncVoid
The program '[18584] dotnet.exe' has exited with code 0 (0x0).

I want more information.

  • If there is no current synchronization context (as in my example), where does the exception occur?
  • What is the difference between async void(without await) andvoid
    • The compiler warns CS1998 C# This async method lacks 'await' operators and will run synchronously.
    • await, , void?
    • async Task await , Task?
  • async void async Task. Task async void, ?

. , - /.

+4
2

( ), ?

, SynchronizationContext.Current null, , SynchronizationContext.Current, new SynchronizationContext(), , " " " ".

, , , , async , , catch.

, : async void . , ; , UI. async void : ( await) . ; , System.Threading.Timer , System.Threading.Timer.

, , void?

async .

?

. async Task - ​​ Task. async/await .

async void async Task.

, .

, async Task ; async void - , #/VB . async/await, F #, Python JavaScript, async void... , , .

async void, ?

.

+5
  • async void - , .
  • async Task - ,
  • async methodName {return default (T); } - T
  • void -
-1

Source: https://habr.com/ru/post/1682021/


All Articles