Подтвердить что ты не робот

Почему я не могу получить исключение из асинхронного кода?

Всюду, где я читаю, говорится, что следующий код должен работать, но это не так.

public async Task DoSomething(int x)
{
   try
   {
      // Asynchronous implementation.
      await Task.Run(() => {
      throw new Exception();
      x++;
      });
   }
   catch (Exception ex)
   {
      // Handle exceptions ?
   }
}

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

4b9b3361

Ответ 1

У вас включен параметр "Только мой код". При этом он рассматривает исключение, необработанное по отношению к "только вашему коду", потому что другой код перехватывает исключение и набивает его внутри Задачи, а затем возвращается к вызову await и поймает ваш catch выражение.

Не будучи прикрепленным в отладчике, оператор catch будет запущен, и он будет работать, как вы ожидаете. Или вы можете просто продолжить работу внутри отладчика, и он будет работать как ожидалось.

Лучше всего просто отключить "Только мой код". ИМО, это вызывает больше путаницы, чем того стоит.

Ответ 2

Ваш код даже не будет компилироваться в настоящий момент, так как оператор x++; недоступен. Всегда обращайте внимание на предупреждения.

Однако, после исправления этого, он отлично работает:

using System;
using System.Threading.Tasks;

class Test
{
    static void Main(string[] args)
    {
        DoSomething(10).Wait();
    }

    public static async Task DoSomething(int x)
    {
        try
        {
            // Asynchronous implementation.
            await Task.Run(() => {
                throw new Exception("Bang!");
            });
        }
        catch (Exception ex)
        {
            Console.WriteLine("I caught an exception! {0}", ex.Message);
        }
    }
}

Вывод:

I caught an exception! Bang!

(Обратите внимание: если вы попробуете приведенный выше код в приложении WinForms, у вас будет тупик, потому что вы будете ждать выполнения задачи, которая должна была вернуться к потоку пользовательского интерфейса. Мы в порядке в консольном приложении поскольку задача будет возобновлена ​​в потоке threadpool.)

Я подозреваю, что проблема - это просто вопрос отладки - отладчик может считать его необработанным, даже если он обрабатывается.

Ответ 3

Как сказал Слэкс, ваш код отлично работает.

Я сильно подозреваю, что вы упростили свой пример и имеете async void в своем коде.

Следующий работает отлично:

private static void Main(string[] args)
{
    CallAsync();
    Console.Read();
}

public static async void CallAsync()
{
    try
    {
        await DoSomething();
    }
    catch (Exception)
    {
        // Handle exceptions ?
        Console.WriteLine("In the catch");
    }
}

public static Task DoSomething()
{
    return Task.Run(() =>
    {
        throw new Exception();
    });
}

Следующий не работает:

private static void Main(string[] args)
{
    CallAsync();
    Console.Read();
}

public static void CallAsync()
{
    try
    {
        DoSomething();
    }
    catch (Exception)
    {
        // Handle exceptions ?
        Console.WriteLine("In the catch");
    }
}

public static async void DoSomething()
{
    await Task.Run(() =>
    {
        throw new Exception();
    });
}

См. http://msdn.microsoft.com/en-us/magazine/jj991977.aspx

Асинхронные методы имеют разную семантику обработки ошибок. Когда исключение выбрасывается из задачи async Task или async Task, что исключение захватывается и помещается в объект Task. С асинхронным методов нет объекта Task, поэтому любые исключения, исключенные из метод async void будет поднят непосредственно на SynchronizationContext, который был активен, когда метод async void начал. Рисунок 2 иллюстрирует, что исключения, выброшенные из асинхронного методы не могут быть пойманы естественным путем.

Ответ 4

Вместо использования await, войдите в свойство Task.Result и поместите туда try и catch. Вы также можете следовать примеру здесь и попробовать этот стиль.

Имейте в виду, что все исключения, брошенные в контексте потока задач, завернуты в AggregateException.

Ответ 5

Исключением не является cuaght. Причина в том, что - когда выполняется инструкция ниже

await Task.Run(() => {
            throw new Exception("Bang!");
        });

его на отдельном потоке. Исключение, возникающее в этом потоке, нечеткое.

измените его так, как показано ниже

await Task.Run(() => {

                try
                {
                    throw new Exception("Bang!");
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);   
                }

        });