第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

為了賬號安全,請及時綁定郵箱和手機(jī)立即綁定

如何使用 C# 在異步代碼中處理異常

標(biāo)簽:
C#

异常处理是一种处理运行时错误的技术,而 异步编程 允许我们在处理资源密集型的业务逻辑时不需要在 Main 方法或者在 执行线程 中被阻塞,值得注意的是,异步方法和同步方法的异常处理机制是不一样的,本篇我们就来讨论下如何在异步方法中处理异常。

异步方法 VS 同步方法 的异常处理

在同步代码中抛出异常,它会一直以冒泡的方式往上抛,直到遇到可以处理这个异常的 catch 块为止,可以想象,异步方法中的异常抛出肯定要比这个复杂。

大家都知道 异步方法 可以有三种返回类型,如:void, Task, Task,当异常方法的返回值是 Task ,Task 的方法中抛出异常的话,这个异常对象会被塞到 AggregateException 对象中,然后包裹在 Task 中进行返回,有些朋友可能要问,如果异步方法中抛出了几个异常怎么办?其实也是一样的道理,这些异常对象都会被塞到 AggregateException 中通过 Task 去返回。

最后,如果异常出现在返回值为 void 的异步方法中,异常是在调用这个异步方法的 SynchronizationContext 同步上下文上触发。

返回 void 异步方法中的异常

下面的程序展示了返回 void 的异步方法中抛出了异常。


    class Program
    {
        static void Main(string[] args)
        {
            ThisIsATestMethod();

            Console.ReadLine();
        }

        public static void ThisIsATestMethod()
        {
            try
            {
                AsyncMethodReturningVoid();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
        private static async void AsyncMethodReturningVoid()
        {
            await Task.Delay(1000);
            throw new Exception("This is an error message...");
        }
    }

从图中可以看到,AsyncMethodReturningVoid 方法抛出的异常会被包裹此方法的 try catch 捕捉到。

返回 Task 的异步方法异常

当异常从返回值为 Task 的异步方法中抛出,这个异常对象会被包裹在 Task 中并且返回给方法调用方,当你用 await 等待此方法时,只会得到一组异常中的第一个被触发的异常,如果有点懵的话,如下代码所示:


    class Program
    {
        static void Main(string[] args)
        {
            ExceptionInAsyncCodeDemo();

            Console.ReadLine();
        }

        public static async Task ExceptionInAsyncCodeDemo()
        {
            try
            {
                var task1 = Task.Run(() => throw new IndexOutOfRangeException("IndexOutOfRangeException is thrown."));
                var task2 = Task.Run(() => throw new ArithmeticException("ArithmeticException is thrown."));
                await Task.WhenAll(task1, task2);
            }
            catch (AggregateException ex)
            {
                Console.WriteLine(ex.Message);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
    }

从上面代码中可以看出 task1 和 task2 都会抛出异常,但在 catch 块中只捕获了 task1 中的异常,这就说明返回值为 Task 的多个异常的方法中,调用方只能截获第一次发生异常的异常对象。

使用 Exceptions 属性 获取所有异常

要想获取已抛出的所有异常,可以利用 Task.Exceptions 属性来获取,下面的代码清单展示了如何在返回 Task 的方法中获取所有的异常信息。


    class Program
    {
        static void Main(string[] args)
        {
            ExceptionInAsyncCodeDemo();

            Console.ReadLine();
        }

        public static async Task ExceptionInAsyncCodeDemo()
        {
            Task tasks = null;
            try
            {
                var task1 = Task.Run(() => throw new IndexOutOfRangeException("IndexOutOfRangeException is thrown."));
                var task2 = Task.Run(() => throw new ArithmeticException("ArithmeticException is thrown."));
                tasks = Task.WhenAll(task1, task2);
                await tasks;
            }
            catch
            {
                AggregateException aggregateException = tasks.Exception;

                foreach (var e in aggregateException.InnerExceptions)
                {
                    Console.WriteLine(e.GetType().ToString());
                }
            }
        }
    }

使用 AggregateException.Handle 处理所有异常

你可以利用 AggregateException.Handle 属性去处理一组异常中的某一个,同时忽略其他你不关心的异常,下面的代码片段展示了如何去实现。


    class Program
    {
        static async Task Main(string[] args)
        {
            await ExceptionInAsyncCodeDemo();
            Console.Read();
        }

        public static async Task ExceptionInAsyncCodeDemo()
        {
            Task tasks = null;
            try
            {
                var task1 = Task.Run(() => throw new IndexOutOfRangeException("IndexOutOfRangeException is thrown."));
                var task2 = Task.Run(() => throw new ArithmeticException("ArithmeticException is thrown."));
                tasks = Task.WhenAll(task1, task2);
                await tasks;
            }
            catch(AggregateException ex)
            {
                AggregateException aggregateException = tasks.Exception;

                foreach (var e in aggregateException.InnerExceptions)
                {
                    Console.WriteLine(e.GetType().ToString());
                }
            }
        }
    }

上面的代码片段表示:IndexOutOfRangeException 会被处理, InvalidOperationException 会被忽略。

最后想说的是,你可以利用 异步编程 来提高程序的扩展性和吞吐率,当你在使用异步方法时,请注意在异步方法中的异常处理语义和同步方法中的异常处理是不一样的。

點(diǎn)擊查看更多內(nèi)容
TA 點(diǎn)贊

若覺得本文不錯,就分享一下吧!

評論

作者其他優(yōu)質(zhì)文章

正在加載中
  • 推薦
  • 評論
  • 收藏
  • 共同學(xué)習(xí),寫下你的評論
感謝您的支持,我會繼續(xù)努力的~
掃碼打賞,你說多少就多少
贊賞金額會直接到老師賬戶
支付方式
打開微信掃一掃,即可進(jìn)行掃碼打賞哦
今天注冊有機(jī)會得

100積分直接送

付費(fèi)專欄免費(fèi)學(xué)

大額優(yōu)惠券免費(fèi)領(lǐng)

立即參與 放棄機(jī)會
微信客服

購課補(bǔ)貼
聯(lián)系客服咨詢優(yōu)惠詳情

幫助反饋 APP下載

慕課網(wǎng)APP
您的移動學(xué)習(xí)伙伴

公眾號

掃描二維碼
關(guān)注慕課網(wǎng)微信公眾號

舉報

0/150
提交
取消