C# 异常处理(一)

  问题一:try-catch-finally  中有return的情况,会如何执行

             很多人都会纠结这么一个问题try-catch-finally中有return的情况,我自己总结如下:

            1.1 如果是值类型的话

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 
 6 namespace 含有return的测试
 7 {
 8     class Program
 9     {
10         static void Main(string[] args)
11         {
12             int j = Test();
13             Console.WriteLine(j);
14            
15         }
16         /// <summary>
17         /// 这个是测试return里面的是值类型就不会对他们有影响呢 
18         /// </summary>
19         /// <returns></returns>
20         static int Test()
21         {
22              int i = 0;
23 
24             try
25             {
26                
27                 return i; //为什么这里要加个return呢
28             }
29             catch (Exception)
30             {
31 
32                 i++;
33                 return i;
34 
35             }
36             finally
37             {
38                 i = i + 2;
39             }
40         
41         }
42         
43 
44     }
45 }

 

    通过上面的代码可以看出,这里的finally执行了之后,对return返回没有影响 return返回结果还是0;

    1.2  返回值是引用类型

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 
 6 namespace 引用类型测试
 7 {
 8     class Program
 9     {
10         static void Main(string[] args)
11         {
12             List<string> strList = Test();
13              foreach (var i in strList)
14             {
15                 Console.WriteLine(i);
16             }
17             Console.ReadKey();
18         }
19         private static List<string> Test()
20         {
21             List<string> strList = new List<string>();
22             strList.Add("aa");
23             strList.Add("bb");
24             strList.Add("cc");
25             try
26             {
27                 //这里没有发生异常的 
28                 strList.Add("trytry");
29                 return strList;
30             }
31             catch (Exception ex)
32             {
33                 strList.Add("zzz");
34                 return strList;
35             }
36             finally
37             {
38                 strList.Add("yyy");
39             }
40         }  
41 
42     }
43 }

输出结果如下:

通过以上两个例子可以总结:  如果是值类型的话,finally里面的改变不会对try或者catch中的return返回值造成影响。

                                              如果是引用类型的话,finally里面的改变会对try或者catch中的return返回值造成影响(除了String外)。

                                              造成这个结果的主要原因就是return返回的是栈中的地址。

   问题二:多个Try catch finally的执行顺序。

         try这个执行顺序不说了。

         catch块:如果Try块中的代码没有抛出异常的话呢,CLR永远都不会执行它的任何Catch块

         如果是不会报异常的话,线程就会跳过catch块,直接执行finally块(如果有的话)。

         但是如果try块里面报了异常的话呢。并且Catch也能捕捉到这个异常(第一层Catch就可以捕捉到)。那就是try catch finally的顺序执行。

         假设第一层Catch没有匹配到,就会继续往上面的抛,直到Catch可以匹配到。如果没有匹配到Catch就直接报异常了,程序崩了(如果没有捕捉到异常的话呢,finally的语句是不会执行的。如果有finally的话,最后面会去执行finally)。

         如果catch第一层没有捕捉到,在第二层也没有捕捉到,在第三层的Catch里面捕捉到这个异常的话呢,会在进入catch之前先之前第一层的finally(如果有),第二层finally执行完了,才去第三层执行对应的catch里面的内容:如下面代码所示:

  
 static void MethodFour()
        {
            try
            {
                throw new NotImplementedException();
            }
            catch(DivideByZeroException ex)
            {

            }
            finally
            {
                Console.WriteLine("最里面的 finally");
            }
        }

         上面这个方法是不会匹配到异常,异常会往上面抛(它的调用如下)

    try
            {
                MethodFour();
                //这里输出的顺序是先finally,再Exception。
            }
            catch(Exception ex)
            {
                //异常会往上抛,在它匹配到这个异常的时候.
                Console.WriteLine($"Exception");
            }
            finally
            {
                Console.WriteLine("最外面的 Finally");
            }

        具体结果如何,大家可以动手试试。

      问题三:很多人说Catch要指定先具体的异常类型,最后再写一个Exception。     

         try块:一般是可能报异常的。每一个try至少有一个catch块或finally块。

         catch块:包含的是响应异常需要执行的代码。如果一个try块里面没有造成异常,CLR永远不会执行它的任何catch块。线程将跳过所有catch块,直接执行finally块(如果有的话)。

         catch关键字后的圆括号中的表达式称为捕捉类型。C#要求捕捉类型必须是System.Exception或者它的派生类型。

          有了这两个基础之后,再解释问题一,CLR是自上而下搜索匹配catch块,所以应该将较具体的异常放在顶部。也就是说首先要出现的是派生度最大的异常类型,接着是它们的基类型(如果有的话),最后是System.Exception(或者是没有指定任何捕捉类型的catch块)。

          那么问题又来了,很多时候,我们是直接一个try{ ...}catch(excepiton ex){ ... } ,和我们上面说的做法(写到具体的异常类型)有多大区别呢。

         直接上例子:

     static void MethodOne()
        {
            try
            {
                int i = 0;
                int j = 10 / i;
            }
            catch(FormatException ex)
            {
                //假设这里多一层比较,再匹配到
            }
            catch (DuplicateWaitObjectException ex)
            {
                //再多一层比较
            }
            catch(DivideByZeroException ex)
            {
               // Console.WriteLine("DivideByZeroException异常");
            }
            catch(Exception ex)
            {
                Console.WriteLine("Exception ONE");
            }
        }
  static void MethodTwo()
        {
            try
            {
                int i = 0;
                int j = 10 / i;
            }
            catch (Exception ex)
            {
              //  Console.WriteLine("Exception TWO");
            }
        }

      上面的例子,跑出来的结果说明(大家动手跑一下),methodone(匹配到具体异常的)要比methondtwo(直接exception)要高效。

 问题四:Throw和Throw ex区别

      每次看到别人写的代码有时候Throw; 有时候又Throw ex;总是充满好奇,他们为什么要这么写,这样写有啥区别呢。下面我们一起来看看究竟。

      1、先说Throw ex会重置异常,异常堆栈信息会重新抛出,这样就会影响我们根据异常信息来定位问题。

      2、Throw 会传递异常,不会重置异常。

      static void TestMethod()
        {
            try
            {
                Console.WriteLine($"ThreadId{Thread.CurrentThread.ManagedThreadId}");
                TestThrow();
            }
            catch (Exception ex)
            {
                Console.WriteLine("除以零报异常了");
                //throw ex;//把异常信息向上抛了。
                throw ex;
            }
            
        }

        static void TestThrow()
        {
            var t = 0;
            var res = 10 / t;
        }

  问题五:对于try catch finally对性能影响一说

  

  //当异常被重置的话呢。
            try
            {

            }
            catch(FormatException ex)
            {
                //这里写一个日志。logHelp.write(ex)
                throw new Exception("格式化异常");
            }
            catch(DivideByZeroException ex)
            {
                //这里写一个日志。logHelp.write(ex)
                throw new Exception("尝试除以零");
            }
            catch(IndexOutOfRangeException ex)
            {
                //这里写一个日志。logHelp.write(ex)
                throw new Exception("索引溢出");
            }
            catch(Exception ex)
            {
                //这里写一个日志。logHelp.write(ex)
                throw new Exception("其他异常");
            }
            finally
            {
                //资源清理
            }

  从上面这段代码,可以看到try catch finally给我们的感觉就是代码结构清晰,分门别类。

     异常的处理好处有如下(个人觉得)

  1、代码可读性很好,正常的逻辑和异常处理,资源清理都分开。

  2、系统可靠性提升了。

  3、链式调用方法可以很轻松的实现了。

       关于性能这一说法:

       一旦异常被抛出去的话,函数也会跟着return,而程序在执行时候,需要处理函数栈的上下文,如果函数栈比较深的话,性能就更加受影响了。从另外一方面来说,如果你的程序报异常了,就应该要停止执行了。程序本来就应该在没有异常的情况下执行的(所以你大部分情况下,程序是不会抛出异常的,对性能的影响也就不那么大了)。

 

      

 

 

         

 

 

转载于:https://www.cnblogs.com/gdouzz/p/4763224.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值