Code Copied

输出自定义异常触发方法、类、堆栈信息

1. 自定义异常说明

C#中的自定义异常一般用于验证业务逻辑的正确性,系统异常一般通过try catch语句块和Exception类或其派生类进行处理,系统异常类型都定义在CLR中。

在定义自定义异常类时应该需要注意以下几点(当然你也可以不必这么做):

    1. 异常类应该声明为可序列化的,即Serializable特性标记
    2.
添加无参的构造方法
    3. 添加参数为string的构造方法
    4. 添加参数为string和Exception的构造方法
    5. 添加参数为SerializationInfo和StreamingContext的序列化构造方法

例如:

[Serializable]
public class CustomException : Exception
{
    public CustomException()
    {
    }

    public CustomException(string message)
        :base (message)
    {
    }

    public CustomException(string message, Exception innerException)
        :base (message, innerException)
    {
    }

    protected CustomException(SerializationInfo info, StreamingContext context)
        : base(info,context)
    {
    }
}

2. 输出异常触发方法、类、堆栈信息

场景描述:在类TestClass中,定义一个私有的InnerMethod()和一个共有的OuterMethod(),OuterMethod()调用InnerMethod(),并在OuterMethod()中捕获异常信息。
下面的示例演示分别演示了自定义异常和系统异常捕捉,并且将异常关键信息用日志方式输出。

public class TestClass
{
    private void InnerMethod(int customerId)
    {
        if (customerId > 1000000)
        {
            throw new CustomException("L0001");
        }
        // Other code
        // Other code
        // Other code
    }

    public void OuterMethod()
    {
        try
        {
            InnerMethod(1000001);
        }
        catch (CustomException ex)
        {
            Logger.Exception(ex);
        }
        catch (Exception ex)
        {
            CustomException cuex = new CustomException("E0001", ex);
            Logger.Exception(cuex);
        }
    }
}

注意:在OuterMethod()中,第2段catch实例化CustomerException时将Exception实例作为其InnerException属性。
Logger类是一个日志记录类,用于记录系统的Info, Warning, Exception等信息。

public class Logger
{

    public static void Info(string message)
    {
        
    }

    public static void Warning(string message)
    {
        
    }

    public static void Exception(CustomException ex)
    {
        Console.WriteLine(ex.TargetSite.Name);
        Console.WriteLine(ex.TargetSite.DeclaringType.Name);
        Console.WriteLine(ex.StackTrace);
    }
}

TargetSite.Name:触发异常的方法名称
TargetSite.DeclaringType.Name:触发异常的类名称
StackTrace:触发异常的堆栈信息

实际应用中我们应该使用log4net或Application Block等类库处理日志

测试1:触发CustomException异常块

当customerId > 1000000时,throw自定义异常CustomException

SNAGHTML156d751

堆栈信息的行号分别标出了InnerMethod和OuterMethod的异常行号。

image

测试2:触发Exception异常块

对TestClass变更一些代码,传入一个customerId为-1的参数

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

namespace Exceptions
{
    public class TestClass
    {
        private void InnerMethod(int customerId)
        {
            if (customerId > 1000000)
            {
                throw new CustomException("L0001");
            }
            if (customerId < 0)
            {
                throw new Exception("Customer id can not be less than 0");
            }
            // Other code
            // Other code
            // Other code
        }

        public void OuterMethod()
        {
            try
            {
                InnerMethod(-1);
            }
            catch (CustomException ex)
            {
                Logger.Exception(ex);
            }
            catch (Exception ex)
            {
                CustomException cuex = new CustomException("E0001", ex);
                Logger.Exception(cuex);
            }
        }
    }
}

CustomException的TargetException属性为null,Logger类调用Exception()方法时出现异常NullReferenceException。

image

由于在InnerException触发的是第2段Exception,throw的是Exception实例,而非CustomException实例,所以CustomerException的TargetSite属性为空。

将Logger类的Exception()方法做一些修改可以避免该方法异常。

public class Logger
{

    public static void Info(string message)
    {
        
    }

    public static void Warning(string message)
    {
        
    }

    public static void Exception(CustomException ex)
    {
        if (ex.TargetSite != null)
        {
            Console.WriteLine(ex.TargetSite.Name);
            Console.WriteLine(ex.TargetSite.DeclaringType.Name);
            Console.WriteLine(ex.StackTrace);
        }
        if (ex.InnerException != null)
        {
            var inner = ex.InnerException;
            Console.WriteLine(inner.TargetSite.Name);
            Console.WriteLine(inner.TargetSite.DeclaringType.Name);
            Console.WriteLine(inner.StackTrace);
        }
    }
}

控制台输出信息:

SNAGHTML17b32ba

堆栈信息对应的代码行:

image

3. 参考和源码

参考链接:http://msdn.microsoft.com/en-us/library/vstudio/ms229064(v=vs.100).aspx
本文源码:http://blog.64cm.com/source/CSharp/Exceptions.zip