当前位置:首页 > C#编程 > C#/.net框架 > 正文内容

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

Jorge2年前 (2022-05-09)C#/.net框架561

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



C#
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。这是从任务中抛出的,它是一个异常集合,可能包含得分多个异常,要求您检查内部异常以查找特定的异常。 像这样:

C#
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应用程序中如何执行此操作:

C#
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方法。

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

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


其它处理方式:

C#
   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语句中记录错误信息

C#
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进行处理。


代码:

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

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

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

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

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

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


#转载请注明出处 www.skcircle.com 《少有人走的路》勇哥的工业自动化技术网站。

扫描二维码推送至手机访问。

版权声明:本文由7点博客发布,如需转载请注明出处。

本文链接:http://6dot.cn/?id=77

标签: .NET.NET框架
分享给朋友:

“C#4.0的并行库TPL,即Task(四)” 的相关文章

C#的propertygrid控件,选择和修改项目时很慢

C#的propertygrid控件,选择和修改项目时很慢

C#的propertygrid控件是很强。可以实现类似Vitual Studio属性面板那样的效果。但是。。。。我们一直痛苦它在选择和修改项目的时候很慢。我的用法是使用控件的SelectObject来绑定数据。C# PgridMotionSpeed.SelectedObject ...

计算代码执行时间,可以精确到十亿分之一秒

计算代码执行时间,可以精确到十亿分之一秒

注:.Net的Stopwatch类可以精确到1/10000毫秒, 有没有更精确的计时吗?见下面的代码。暂时没试过效果,大家可以试下。计算某个代码片段的执行时间,精确到CPU执行一条指令所用的时间(十亿分之一秒),可用于精确计算某个算法的执行时间。 代码:C#using Syste...

c#——表达式树在LINQ动态查询

c#——表达式树在LINQ动态查询

一般如果逻辑比较简单,只是存在有的情况多一个查询条件,有的情况不需要添加该查询条件简单方式这样操作就可以了C#public IQueryable<FileImport> DynamicChainedSyntax (IQueryable<FileImport&g...

C# 异步和等待,async/await

C# 异步和等待,async/await

 首先,重点是:异步将从根本上改变大多数代码的编写方式。是的,我相信 async/await 会比 LINQ 产生更大的影响。理解异步将在短短几年内成为基本必需品。关键字介绍让我们直接开始吧。我将使用一些稍后将阐述的概念——请继续阅读第一部分。异步方法看起来像这样:public ...

.NET(C#) TPL:Task中未觉察异常和TaskScheduler.UnobservedTaskException事件

.NET(C#) TPL:Task中未觉察异常和TaskScheduler.UnobservedTaskException事件

当你在一个Task执行中抛出异常,比如:C#Task.Factory.StartNew(() =>{    throw new Exception();});运行该方法,没有任何异常抛出。事实上此时Task的异常处于未觉察状...

C# .Net 多进程同步 通信 共享内存 内存映射文件 Memory Mapped

C# .Net 多进程同步 通信 共享内存 内存映射文件 Memory Mapped

 节点通信存在两种模型:共享内存(Shared memory)和消息传递(Messages passing)。        内存映射文件对于托管世界的开发人员来说似乎很陌生,但它确实已经是很远古的技术了,而且在操作系统...

发表评论

访客

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