Proper way of handling exception in task continuewith

后端 未结 6 1562
悲&欢浪女
悲&欢浪女 2020-12-07 22:06

Please have a look at the following code-

static void Main(string[] args)
{
    // Get the task.
    var task = Task.Factory.StartNew(() => { r         


        
相关标签:
6条回答
  • 2020-12-07 22:39

    As of .Net 4.5, you can use AggregateException.GetBaseException() to return " the root cause of this exception".

    https://docs.microsoft.com/en-us/dotnet/api/system.aggregateexception.getbaseexception?view=netframework-4.7.2

    The documentation seems to be a little off though. It claims to return another AggregateException. However I think you'll find that it returns the ArgumentException that was thrown.

    0 讨论(0)
  • 2020-12-07 22:43

    The "One or more errors occurred" comes from a wrapper exception that is made by the task pool. Use Console.WriteLine(t.Exception.ToString()) to print the whole exception if you need it.

    IDEs may automatically capture all exceptions no matter whether they were handled or not.

    0 讨论(0)
  • 2020-12-07 22:49

    What you have there is an AggregateException. This is thrown from tasks and requires you to check the inner exceptions to find specific ones. Like this:

    task.ContinueWith(t =>
    {
        if (t.Exception is AggregateException) // is it an AggregateException?
        {
            var ae = t.Exception as AggregateException;
    
            foreach (var e in ae.InnerExceptions) // loop them and print their messages
            {
                Console.WriteLine(e.Message); // output is "y" .. because that's what you threw
            }
        }
    },
    TaskContinuationOptions.OnlyOnFaulted);
    
    0 讨论(0)
  • 2020-12-07 22:53

    Since you are using tasks you should get AggregateException which wraps all exceptions occured during execution. You see One or more errors occurred message, because it's default output of AggregateException.ToString() method.

    You need Handle method of the exception's instance.

    Also see the right approach to handle such exceptions here.

    0 讨论(0)
  • 2020-12-07 23:00

    You probably don't need separate OnlyOnFaulted and OnlyOnRanToCompletion handlers, and you're not handling OnlyOnCanceled. Check this answer for more details.

    But when debugging in IDE, A IDE exception message ("Unhandled exception in user code" ) appears when the control executes the line

    You see the exception under debugger because you probably have enabled it in Debug/Exceptions options (Ctrl+Alt+E).

    If I continue from there on, the program does not crash and displays the same output as release mode. Is this proper way to handle exception?

    An exception which was thrown but not handled inside a Task action will not be automatically re-thrown. Instead, it be wrapped for future observation as Task.Exception (of type AggregateException). You can access the original exception as Exception.InnerException:

    Exception ex = task.Exception;
    if (ex != null && ex.InnerException != null)
        ex = ex.InnerException;
    

    To make the program crash in this case, you actually need to observe the exception outside the task action, e.g. by referencing the Task.Result:

    static void Main(string[] args)
    {
        // Get the task.
        var task = Task.Factory.StartNew<int>(() => { return div(32, 0); });
    
        // For error handling.
        task.ContinueWith(t => { Console.WriteLine(t.Exception.Message); }, 
            TaskContinuationOptions.OnlyOnFaulted);
    
        // If it succeeded.
        task.ContinueWith(t => { Console.WriteLine(t.Result); }, 
            TaskContinuationOptions.OnlyOnRanToCompletion);
    
        Console.ReadKey();
    
        Console.WriteLine("result: " + task.Result); // will crash here
    
        // you can also check task.Exception
    
        Console.WriteLine("Hello");
    }
    

    More details: Tasks and Unhandled Exceptions, Task Exception Handling in .NET 4.5.

    Updated to address the comment: here is how I would do this in a UI app with .NET 4.0 and VS2010:

    void Button_Click(object sender, EventArgs e)
    {
        Task.Factory.StartNew<int>(() => 
        {
            return div(32, 0); 
        }).ContinueWith((t) =>
        {
            if (t.IsFaulted)
            {
                // faulted with exception
                Exception ex = t.Exception;
                while (ex is AggregateException && ex.InnerException != null)
                    ex = ex.InnerException;
                MessageBox.Show("Error: " + ex.Message);
            }
            else if (t.IsCanceled)
            {
                // this should not happen 
                // as you don't pass a CancellationToken into your task
                MessageBox.Show("Canclled.");
            }
            else
            {
                // completed successfully
                MessageBox.Show("Result: " + t.Result);
            }
        }, TaskScheduler.FromCurrentSynchronizationContext());
    }
    

    For as long as you target .NET 4.0 and you want the .NET 4.0 behavior for unobserved exceptions (i.e., re-throw when task gets garbage-collected), you should explicitly configure it in the app.config:

    <?xml version="1.0" encoding="utf-8"?>
    <configuration>
      <startup>
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
      </startup>
      <runtime>
        <ThrowUnobservedTaskExceptions enabled="true"/>
      </runtime>
    </configuration>
    

    Check this for more details:

    Unobserved task exceptions in .NET4

    0 讨论(0)
  • 2020-12-07 23:01
            try
            {
                var t1 = Task.Delay(1000);
    
                var t2 = t1.ContinueWith(t =>
                {
                    Console.WriteLine("task 2");
                    throw new Exception("task 2 error");
                }, TaskContinuationOptions.OnlyOnRanToCompletion);
    
                var t3 = t2.ContinueWith(_ =>
                {
                    Console.WriteLine("task 3");
                    return Task.Delay(1000);
                }, TaskContinuationOptions.OnlyOnRanToCompletion).Unwrap();
    
                // The key is to await for all tasks rather than just
                // the first or last task.
                await Task.WhenAll(t1, t2, t3);
            }
            catch (AggregateException aex)
            {
                aex.Flatten().Handle(ex =>
                    {
                        // handle your exceptions here
                        Console.WriteLine(ex.Message);
                        return true;
                    });
            }
    
    0 讨论(0)
提交回复
热议问题