简体   繁体   中英

Handling async exceptions

I'm wondering how I can let this code fall in the catch of 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);
    }
}

fiddle

The external code should return handle the error path and return Task.FromException ?
Pass a Func<Task<bool>> ?

My recommendation would be to change your PassThrough method to take a Func<Task<bool>> instead of a Task<bool> . This way, you can capture exceptions arising both from the synchronous part of your Test method, as well as the asynchronous task it launches. An added advantage is that asynchronous methods (defined using async and await ) can be directly cast to Func<Task> or 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);
    }
}

Adding to Douglas 's answer.

Only catch exceptions if you are able to do something meaningful with them and you can manage them at that level.

Task.FromException basically just places the exception on a task which you would usually return. However, in this case the Async Await Pattern already does this for you. ie If you just let it fail, the exception will get placed on the task anyway, so there seems no real reason from your code to catch anything.

The only pertinent place you have to think about catching exceptions is in async void as they run unobserved and can cause issues when an exception is thrown

In the following line you are awaiting the PassThrough , not the Test .

await PassThrough(Test());

You could await both if you wanted:

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

...but in both cases the Test will be invoked first. And since it throws an exception, the PassThrough will never be invoked. This is the reason you don't see the "caught in PassThrough" message. The execution never enters this method.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM