Обработка асинхронных исключений - PullRequest
1 голос
/ 08 апреля 2019

Мне интересно, как я могу позволить этому коду попасть в 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?
Pass Func<Task<bool>>?

Ответы [ 3 ]

2 голосов
/ 08 апреля 2019

Я бы порекомендовал изменить ваш 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);
    }
}
1 голос
/ 08 апреля 2019

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

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

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

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

0 голосов
/ 08 апреля 2019

В следующей строке вы ожидаете 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» . Выполнение никогда не входит в этот метод.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...