C#4.0的并行库TPL,即Task(四)

C#4.0的并行库TPL,即Task(一)http://47.98.154.65/?id=1793

C#4.0的并行库TPL,即Task(二) http://47.98.154.65/?id=1798

C#4.0的并行库TPL,即Task(三) http://47.98.154.65/?id=1808

C#4.0的并行库TPL,即Task(四)  http://47.98.154.65/?id=1815

C#4.0的并行库TPL,即Task(五) http://47.98.154.65/?id=1816


这一篇继续Task异常处理的话题:


代码:

下面的异常处理中,(1)(2)(3)演示了3种处理异常办法。这些地方都会断下来。


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication20
{
    class Program
    {
        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);

            task.ContinueWith(t =>
            {
                if (t.Exception is AggregateException) 
                {
                    var ae = t.Exception as AggregateException;

                    foreach (var e in ae.InnerExceptions) 
                    {
                        Console.WriteLine(e.Message); //(1)
                    }
                }
            },
            TaskContinuationOptions.OnlyOnFaulted);


            task.ContinueWith((t) =>
            {
                if (t.IsFaulted)
                {
                    // (2)
                    Exception ex = t.Exception;
                    while (ex is AggregateException && ex.InnerException != null)
                        ex = ex.InnerException;
                    var s1=("Error: " + ex.Message);
                }
                else if (t.IsCanceled)
                {
                    var s2=("Canclled.");
                }
                else
                {
                    // completed successfully
                    var s3=("Result: " + t.Result);
                }
            });
            try
            {
                Console.WriteLine("result: " + task.Result);
            }
            catch (AggregateException aex)
            {
                aex.Flatten().Handle(ex =>
                {
                    // (3)
                    Console.WriteLine(ex.Message);
                    return true;
                });
            }
            Console.ReadKey();
            Console.WriteLine("Hello");
            Console.ReadKey();
        }

        private static int div(int x, int y)
        {
            if (y == 0)
            {
                throw new ArgumentException("y");
            }
            return x / y;
        }

    }
}


下面详细介绍一个3种处理方式:


(1)

自己处理 AggregateException。这是从任务中抛出的,它是一个异常集合,可能包含得分多个异常,要求您检查内部异常以查找特定的异常。 像这样:

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);


(2)

这种方式是在具有.NET 4.0和VS2010的UI应用程序中如何执行此操作:

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());
}




(3)

由于是task任务,因此应该获得AggregateException异常,该异常将包装在执行过程中发生的所有异常。 您会看到One or more errors occurred消息,因为它是AggregateException.ToString()方法的默认输出。

您需要异常实例的Handle方法。

另请参见此处处理此类异常的正确方法。

 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;
                });
        }


其它处理方式:

   try
                {
                    mr[1].WaitOne();
                    TryExecuteTask(task);
                    task.ContinueWith(t => (serialUnitCTS.Token), TaskContinuationOptions.OnlyOnFaulted);
                    task.Wait();
                }
                catch (AggregateException ex)
                {
                    //AggregateException是task的异常集合
                    ex.Handle(predicate: e =>
                     {
                         Console.WriteLine(e.Message);
                         return true;
                     });
                }
                finally
                {
                }


另外在网上看到一个处理异常的技巧,摘录如下:


在async方法中,发生一个异常时,代码并不会直接跳到catch语句中去,而是继续执行,所以到最后catch语句中得到的错误信息是one or more exceptions occurs…

这样的设计给我们带来了麻烦就是传统的try/catch方法得到的无法得到具体的错误信息。

【解决方法】


在catch语句中记录错误信息

if (e is AggregateException)
{
AggregateException ae = (AggregateException)e;
ae.Handle((x) =>
{
exception = x.Message;
return true; // Let anything else stop the application.
});
}
else
{
exception = e.Message;
}

在 catch语句中取到AggregateException的信息(类似解决方法1),然后重新抛出一个带有具体错误信息的异常给调用者。

将异常转成AggregateException后,可以取到InnerException或者InnerExceptions, 然后再用解决方法1或者2进行处理。


本文出自勇哥的网站《少有人走的路》wwww.skcircle.com,转载请注明出处!讨论可扫码加群:

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

会员中心
搜索
«    2025年4月    »
123456
78910111213
14151617181920
21222324252627
282930
网站分类
标签列表
最新留言
    热门文章 | 热评文章 | 随机文章
文章归档
友情链接
  • 订阅本站的 RSS 2.0 新闻聚合
  • 扫描加本站机器视觉QQ群,验证答案为:halcon勇哥的机器视觉
  • 点击查阅微信群二维码
  • 扫描加勇哥的非标自动化群,验证答案:C#/C++/VB勇哥的非标自动化群
  • 扫描加站长微信:站长微信:abc496103864
  • 扫描加站长QQ:
  • 扫描赞赏本站:
  • 留言板:

Powered By Z-BlogPHP 1.7.2

Copyright Your skcircle.com Rights Reserved.

鄂ICP备18008319号


站长QQ:496103864 微信:abc496103864