Необработанное исключение в асинхронном вызове делегата - PullRequest
2 голосов
/ 13 июля 2011

Я пытаюсь перехватить необработанные исключения из асинхронного вызова делегата. Следующая программа иллюстрирует проблему. Я получаю следующий вывод:

Delegate called.
Unhandled exception: an exception.

или

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

или

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

Различные результаты связаны с проблемами синхронизации. Как исправить звонок?

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");
        }
    }
}

1 Ответ

2 голосов
/ 13 июля 2011

При асинхронном вызове делегата у вас есть два варианта.

Вариант 1: обратного вызова нет. Я подозреваю, что это то, что вы пытаетесь сделать.

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)
{
    //
}

Вариант 2: обратный вызов.

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.

Обе формы верны - какая из них вы используете, зависит от того, что вы делаете. Как правило, они не объединяются, как вы.

...