C#异常:throw,throw ex,throw new Exception(..)

Posted by zyuzhi on September 29, 2016

最近看其他人写的C#代码,异常抛出的方式格式各样。总结了三种方式及其优劣:

  1. throw

    1
    2
    3
    4
    5
    6
    7
    8
    
    try
    {
            do_something();
    }
    catch
    {
            throw;
    }
    

    这种方式是将原先的异常再次抛出(rethrow),且不会重置异常的堆栈信息(在原先的堆栈信息上增加了当前的异常信息)。是最为推荐的异常抛出方式。

  2. throw new Exception(…)

    1
    2
    3
    4
    5
    6
    7
    8
    
    try
    {
            do_something();
    }
    catch (Exception ex)
    {
            throw Exception("exception", ex);
    }
    

    这种异常抛出方式是将原先的异常经过包装后再抛出,将原先的异常放在新异常的内部异常堆栈中(ex.InnerException
    PS: 下面异常抛出方式不要使用!!,没有任何异常信息。

    1
    2
    3
    4
    5
    6
    7
    8
    
    try
    {
            do_something();
    }
    catch (Exception ex)
    {
            throw Exception("exception");
    }
    
  3. throw ex

    1
    2
    3
    4
    5
    6
    7
    8
    
    try
    {
            do_something();
    }
    catch (Exception ex)
    {
            throw ex;
    }
    

    这种异常抛出方式重置了堆栈信息,不要使用!

测试

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;

namespace ExceptionDemo
{
    class Program
    {
        static void ThrowException1()
        {
            try
            {
                Console.WriteLine("throw");
                ProduceException();
            }
            catch (Exception)
            {
                throw;
            }
        }

        static void ThrowException2()
        {
            try
            {
                Console.WriteLine("throw new Exception(\"ProduceException\", ex)");
                ProduceException();
            }
            catch (Exception ex)
            {
                throw new Exception("ProduceException", ex);
            }
        }

        static void ThrowException3()
        {
            try
            {
                Console.WriteLine("throw new Exception(\"ProduceException\")");
                ProduceException();
            }
            catch (Exception ex)
            {
                throw new Exception("ProduceException");
            }
        }

        static void ThrowException4()
        {
            try
            {
                Console.WriteLine("throw ex");
                ProduceException();
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        static int ProduceException()
        {
            int a = 0;
            int b = 1;
            return b/a;
        }
        static void Main(string[] args)
        {
            var funcList = new List<Action>
            {
                ThrowException1,
                ThrowException2,
                ThrowException3,
                ThrowException4,
            };
            foreach (var action in funcList)
            {
                try
                {
                    action();
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex);
                }
                Console.WriteLine();
                Console.WriteLine();
            }
        }
    }
}

结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
throw
System.DivideByZeroException: 尝试除以零。
   在 ExceptionDemo.Program.ProduceException() 位置 E:\ExceptionDemo\Program.cs:行号 68
   在 ExceptionDemo.Program.ThrowException1() 位置 E:\ExceptionDemo\Program.cs:行号 21
   在 ExceptionDemo.Program.Main(String[] args) 位置 E:\ExceptionDemo\Program.cs:行号 83


throw new Exception("ProduceException", ex)
System.Exception: ProduceException ---> System.DivideByZeroException: 尝试除以零。
   在 ExceptionDemo.Program.ProduceException() 位置 E:\ExceptionDemo\Program.cs:行号 68
   在 ExceptionDemo.Program.ThrowException2() 位置 E:\ExceptionDemo\Program.cs:行号 30
   --- 内部异常堆栈跟踪的结尾 ---
   在 ExceptionDemo.Program.ThrowException2() 位置 E:\ExceptionDemo\Program.cs:行号 34
   在 ExceptionDemo.Program.Main(String[] args) 位置 E:\ExceptionDemo\Program.cs:行号 83


throw new Exception("ProduceException")
System.Exception: ProduceException
   在 ExceptionDemo.Program.ThrowException3() 位置 E:\ExceptionDemo\Program.cs:行号 47
   在 ExceptionDemo.Program.Main(String[] args) 位置 E:\ExceptionDemo\Program.cs:行号 83


throw ex
System.DivideByZeroException: 尝试除以零。
   在 ExceptionDemo.Program.ThrowException4() 位置 E:\ExceptionDemo\Program.cs:行号 60
   在 ExceptionDemo.Program.Main(String[] args) 位置 E:\ExceptionDemo\Program.cs:行号 83

结论

异常抛出的方式 推荐使用
throw; GOOD
throw new Exception("msg", ex); GOOD
throw new Exception("msg"); BAD
throw ex; BAD