157 recommendations for writing high-quality code to improve C # programs--Recommendations for exception handling in 85:task

Source: Internet
Author: User

Recommended exception Handling in 85:task

At any time, exception handling is a very important aspect. This is especially true in multi-threading and parallel programming. If you do not handle the exceptions in these background tasks, the application will exit inexplicably. Handling exceptions that are not the main thread (if it is a form program, which is the main thread of the UI), the final approach is to wrap it on the main thread.

In the Task Parallel library, you can catch a AggregateException exception if you run a method such as wait, WaitAny, WaitAll, or the result property on the task. The aggregateexception exception can be seen as the topmost exception in the Task Parallel library programming. The exceptions that are caught in the task should eventually be wrapped in aggregateexception. A simple processing example of a task Parallel library exception is as follows:

Static voidMain (string[] args) {Task T=NewTask (() =        {              Throw NewException ("unknown exception generated in task parallel encoding");      });       T.start (); Try      {          //If there is result, result can be obtainedt.wait (); }      Catch(AggregateException e) {foreach(varIteminche.innerexceptions) {Console.WriteLine ("Exception type: {0}{1} from: {2}{3} exception content: {4}", item. GetType (), Environment.NewLine,item. Source, Environment.NewLine, item.          Message); }} Console.WriteLine ("The main thread ends immediately");  Console.readkey (); } 

The above code output:
Exception type: System.Exception
From: ConsoleApplication3
Exception content: Unknown exception generated in task parallel encoding
The main thread ends immediately


You may have noticed that although you run the wait, WaitAny, WaitAll method, or the result property to get exception information for the task, it blocks the current thread. This is often not what we want to see, how can we deliberately wait to get an exception? In this case, consider a function of the task type in the parallel Library: a new successor will solve the waiting problem:

Static voidMain () {Task T=NewTask (() =    {          Throw NewException ("unknown exception generated in task parallel encoding");      });      T.start (); Task Ttend= T.continuewith (Task) = =    {          foreach(Exception Iteminchtask. Exception.innerexceptions) {Console.WriteLine ("Exception type: {0}{1} from: {2}{3} exception content: {4}", item. GetType (), Environment.NewLine,item. Source, Environment.NewLine, item.          Message);       }}, taskcontinuationoptions.onlyonfaulted); Console.WriteLine ("The main thread ends immediately");  Console.readkey (); }  

The output is:
The main thread ends immediately
Exception type: System.Exception
From: ConsoleApplication3
Exception content: Unknown exception generated in task parallel encoding


The above method solves the problem of the main thread wait, but we will find out that the exception handling is not back to the main thread, it is still in thread pool. In some situations, such as the handling of specific exceptions in business logic, this is the way to be done, and we encourage this usage. But obviously, more often than not, we need to further encapsulate exception handling to the main thread.

The task does not provide an interface that wraps exceptions in a task to the main thread. One possible approach is to still use a wait-like approach to achieve this. In the code at the beginning of this recommendation, it is not advisable to use the wait method for the main task. Because the main work task may persist for a long time, it will block the caller and make the caller feel intolerable. In the second code of this recommendation, the new task only finishes handling exceptions, which means that the new task does not last longer, so it is tolerable for the caller to maintain the wait on the new task. So, we can use this method to wrap the exception into the main thread:

Static voidMain (string[] args) {Task T=NewTask (() =    {          Throw NewInvalidOperationException ("unknown exception generated in task parallel encoding");      });      T.start (); Task Ttend= T.continuewith (Task) = =    {          Throwtask.      Exception;      }, taskcontinuationoptions.onlyonfaulted); Try{tend.wait (); }      Catch(aggregateexception err) {foreach(varIteminchErr. InnerExceptions) {Console.WriteLine ("Exception type: {0}{1} from:{2}{3} Exception Content: {4}", item. Innerexception.gettype (),Environment.NewLine, item. Innerexception.source, Environment.NewLine, item.          Innerexception.message); }} Console.WriteLine ("The main thread ends immediately");  Console.readkey (); } 

The output is:
Exception type: System.InvalidOperationException
From: ConsoleApplication3
Exception content: Unknown exception generated in task parallel encoding
The main thread ends immediately

The story does not end here.
Calling the wait method on a thread (or seeking result) is not the best approach because it blocks the main thread, and the CLR will start the thread pool threads in the background to do extra work. If you want to wrap an exception to the main thread, the other way is to use event notification:

Static EventEventhandler<aggregateexceptionargs>aggregateexceptioncatched;  Public classAggregateexceptionargs:eventargs { PublicAggregateException aggregateexception{Get;Set; } }   Static voidMain (string[] args) {aggregateexceptioncatched+ = Eventhandler<aggregateexceptionargs>(program_aggregateexceptioncatched); Task T=NewTask (() =    {          Try          {              Throw NewInvalidOperationException ("unknown exception generated in task parallel encoding"); }          Catch(Exception err) {Aggregateexceptionargs Errargs=NewAggregateexceptionargs () {aggregateexception=Newaggregateexception (Err)}; Aggregateexceptioncatched (NULL, Errargs);      }      });       T.start (); Console.WriteLine ("The main thread ends immediately");   Console.readkey (); }   Static voidProgram_aggregateexceptioncatched (Objectsender, Aggregateexceptionargs e) {      foreach(varIteminche.aggregateexception.innerexceptions) {Console.WriteLine ("Exception type: {0}{1} from: {2}{3} exception content: {4}", item. GetType (), Environment.NewLine, item. Source, Environment.NewLine, item.      Message); }  } 

In this example, we declare a delegate aggregateexceptioncatchhandler, which accepts two parameters, one is the notifier of the event, and the other is the event variable Aggregateexceptionargs. Aggregateexceptionargs is a newly created type for wrapping exceptions. In the main thread, we assign an event-handling method program_aggregateexceptioncatched to the event aggregateexceptioncatched, and the code raises the event when task tasks catch an exception.

This approach does not block the main thread at all. If you are working with the UI interface in an event-handling method in a WinForm or WPF form program, you can also give the exception information to the form's threading model to handle. Therefore, it is ultimately recommended that you use the model of event notification to handle exceptions in a task.

Note The Task Scheduler TaskScheduler provides a feature that has a static event for handling uncaught exceptions. This is generally not recommended because event callbacks occur when garbage collection occurs. As follows:

Static voidMain () {taskscheduler.unobservedtaskexception+=Neweventhandler<Unobservedtaskexceptioneventargs>(taskscheduler_unobservedtaskexception); Task T=NewTask (() =    {          Throw NewException ("unknown exception generated in task parallel encoding");      });      T.start ();      Console.readkey ();      T.dispose (); T=NULL; //GC.  Collect (0); Console.WriteLine ("The main thread ends immediately");  Console.readkey (); }   Static voidTaskscheduler_unobservedtaskexception (Objectsender, Unobservedtaskexceptioneventargs e) {      foreach(Exception Iteminche.exception.innerexceptions) {Console.WriteLine ("Exception type: {0}{1} from: {2}{3} exception content: {4}", item. GetType (), Environment.NewLine, item. Source, Environment.NewLine, item.      Message); }      //identifies the exception as having been observede.setobserved (); } 

The result of this code run does not output exception information, because there is no garbage collection at the time of the exception (the garbage collection time is determined by the CLR). You must remove the comment for Gc.collect (0) and force garbage collection to observe the exception information. This is also the limitation of this approach.

Turn from: 157 recommendations for writing high-quality code to improve C # programs Minjia

157 recommendations for writing high-quality code to improve C # programs--Recommendations for exception handling in 85:task

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.