Обработка асинхронных исключений

Мне интересно, как я могу позволить этому коду попасть в catch из PassThrough?

using System;
using System.Threading.Tasks;

public class Program
{
    public static async Task Main(string[] args)
    {
        try
        {
            await PassThrough(Test());
        } catch (Exception) {
            Console.WriteLine("caught at invocation");
        }

        Console.ReadLine();
    }

    public static async Task PassThrough(Task<bool> test)
    {
        try
        {
            var result = await test.ConfigureAwait(false);

            // still need to do something with result here...
        }
        catch
        {
            Console.WriteLine("never caught... :(");
        }
    }

    /// external code!
    public static Task<bool> Test()
    {
        throw new Exception("something bad");

        // do other async stuff here
        // ...

        return Task.FromResult(true);
    }
}

рабочий пример

Внешний код должен возвращать дескриптор пути ошибки и возвращать Task.FromException?
Передать Func<Task<bool>>?

Вероятно, вам также следует изменить точку входа на public static async Task Main(), если вы используете версию фреймворка, которая ее поддерживает.

Bradley Uffner 08.04.2019 12:26

@BradleyUffner обновлено

grmbl 08.04.2019 12:40
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
2
192
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Добавление к ответу Дуглас.

Перехватывайте исключения только в том случае, если вы можете сделать с ними что-то значимое и можете управлять ими на этом уровне.

Task.FromException в основном просто помещает исключение в задачу, которую вы обычно возвращаете. Однако в этом случае Шаблон асинхронного ожидания уже делает это за вас. т. е. если вы просто позволите ему потерпеть неудачу, исключение все равно будет помещено в задачу, поэтому, похоже, в вашем коде нет реальной причины что-либо ловить.

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

Ответ принят как подходящий

Я бы порекомендовал изменить ваш метод PassThrough, чтобы взять Func<Task<bool>> вместо Task<bool>. Таким образом, вы можете перехватывать исключения, возникающие как в синхронной части вашего метода Test, так и в асинхронной задаче, которую он запускает. Дополнительным преимуществом является то, что асинхронные методы (определенные с помощью async и await) могут быть напрямую приведены к Func<Task> или Func<Task<TResult>>.

using System;
using System.Threading.Tasks;

public class Program
{
    public static async Task Main()
    {
        try
        {
            await PassThrough(Test);   
            // Note that we are now passing in a function delegate for Test,
            // equivalent to () => Test(), not its result.
        } 
        catch (Exception) 
        {
            Console.WriteLine("caught at invocation");
        }

        Console.ReadLine();
    }

    public static async Task PassThrough(Func<Task<bool>> test)
    {
        try
        {
            var task = test();   // exception thrown here
            var result = await task.ConfigureAwait(false);

            // still need to do something with result here...
        }
        catch
        {
            Console.WriteLine("caught in PassThrough");
        }
    }

    /// external code!
    public static Task<bool> Test()
    {
        throw new Exception("something bad");

        // do other async stuff here
        // ...

        return Task.FromResult(true);
    }
}

В следующей строке вы ожидаете PassThrough, а не Test.

await PassThrough(Test());

Вы можете ждать обоих, если хотите:

await PassThrough(await Test()); // also need to change the signature of PassThrough from Task<bool> to bool.

... но в обоих случаях Test будет вызываться первым. И поскольку он выдает исключение, PassThrough никогда не будет вызван. По этой причине вы не видите сообщение "пойман в PassThrough". Выполнение никогда не входит в этот метод.

Другие вопросы по теме