Stefan
Stefan

Reputation: 4206

Unhandled exception in asynchronous delegate call

I'm trying to catch unhandled exceptions from an asynchronous delegate call. The following program illustrates the issue. I get the following output:

Delegate called.
Unhandled exception: an exception.

or

Delegate called.
EndInvoke() threw an exception: an exception.
Program ended.

or

Delegate called.
EndInvoke() threw an exception: an exception.
Program ended.
Unhandled exception: an exception.

The different results are due to the synchronization issues. How to fix the call?

using System;

namespace AsyncCallback
{
    public delegate void SampleDelegate();

    public class Program
    {
        private static SampleDelegate sampleDelegate;

        public static void Main(string[] args)
        {
            AppDomain.CurrentDomain.UnhandledException += UnhandledException;

            sampleDelegate = ThrowException;
            var result = sampleDelegate.BeginInvoke(Callback, null);

            Console.WriteLine("Delegate called.");

            result.AsyncWaitHandle.WaitOne();

            Console.WriteLine("Program ended.");
        }

        private static void Callback(IAsyncResult result)
        {
            try
            {
                sampleDelegate.EndInvoke(result);
                Console.WriteLine("EndInvoke() completed.");
            }
            catch (Exception ex)
            {
                Console.WriteLine("EndInvoke() threw an exception: {0}.", ex.Message);
                throw;
            }
        }

        private static void UnhandledException(object sender, UnhandledExceptionEventArgs e)
        {
            Console.WriteLine("Unhandled exception: {0}.", (e.ExceptionObject as Exception).Message);
        }

        private static void ThrowException()
        {
            throw new Exception("an exception");
        }
    }
}

Upvotes: 2

Views: 2647

Answers (1)

Cory Nelson
Cory Nelson

Reputation: 30001

When calling a delegate asynchronously, you have two options.

Option 1: no callback. I suspect this is what you're trying to do.

SomeDelegate d;

IAsyncResult res = d.BeginInvoke(null, null);

//..do some other work in the meantime.

try
{
    // EndInvoke will wait until execution completes.
    // WaitHandle use not needed!
    d.EndInvoke(res);
}
catch(Exception ex)
{
    //
}

Option 2: callback.

SomeDelegate d;

d.BeginInvoke(res =>
{
    // this is called once the delegate completes execution.

    try
    {
        d.EndInvoke(res);
    }
    catch(Exception ex)
    {
        //
    }
}, null);

//..do some other work in the meantime.

// everything pertaining to the delegate's completion is done in the callback.
// no exception handling should be done here.

Both forms are correct -- whichever one you use depends on what you're doing. They're not normally combined, as you have done.

Upvotes: 2

Related Questions