目录结构:

contents structure [+]

在这篇文章中,笔者会阐述C#中的异常。C#是一门面向对象的语言,面向对象编程极大的提高了开发人员的效率。
比如:

Boolean b= "JReE".Substring(1, 1).ToUpper().EndsWith("E");//true

很容易书写这行代码,也很容易维护和阅读。但是这有一个前提,就是不发生错误,但是错误总是存在的。.NET Framework通过异常来处理这个问题。

以下C#代码展示了异常处理的标准用法:

public void SomeMethod() {
    try
    {
        //需要得体的进行恢复/清理的代码放在这里
    }
    catch (InvalidOperationException e)
    {
        //从InvalidOperationException恢复的代码放在这里
    }
    catch (IOException e)
    {
        //从IOException恢复的代码放在这里
    }
    catch
    {
        //除了上述异常的所有异常恢复都放在这里
        ...
        //通常情况下,若什么异常都捕捉,那么需要重新抛出异常
        throw;
    }
    finally {
        //对try块中的使用到的资源进行清理
        //这里的代码总是执行
    }
    //如果try块没有抛出异常,或是某个catch块捕捉到异常,但没有抛出,那么执行以下的代码
    ...
}

1.1 try块

如果代码需要执行一般性的恢复操作,需要进行资源清理,或者两者都需要。那么就应该放到try块中,然后从catch块中恢复,从finally块中清理资源。
C#的编译器不会强制要求进行异常捕获,这一点没有java支持的好。
例如:

static void SomeMethod() {
    throw new InvalidCastException("类型转化失败");
}

在这里定义了一个SomeMethod方法,调用者可以直接使用SomeMethod方法,不需要进行捕获,可以正常通过编译。通常情况下,可以为方法添加注释,在Visual Studio开发时候就可以提醒开发人员,该方法抛出那些异常。

/// <summary>
/// 方法测试
/// </summary>
/// <exception cref="System.InvalidCastException">类型转化失败时抛出</exception>
static void SomeMethod() {
    throw new InvalidCastException("类型转化失败");
}

如果你没有注释方法的异常信息,那么你代码的调用者就不知道你的代码可能会抛出那些异常,就不能针对性地从异常中恢复。
开发人员若是不知道这些信息,为了增强程序的健壮性,就会使用catch(Exception e)的语言,但这样的语句在开发中是应该避免的。

1.2 catch块

catch块中是响应异常需要执行的代码。一个try块可以关联至少0个catch块。如果try块中的代码抛出执行异常,那么不会执行catch块。catch关键值里面圆括号的表达式被称为捕捉类型,C#要求所以的异常类型必须是System.Exception派生的。

1.3 finally块

finally块中的代码是保证是会执行的。一般在finnaly块中执行try块所需要执行的资源清理操作。
例如:

    FileStream file = null;
    try
    {
        file = new FileStream("test.txt", FileMode.Open);
    }
    catch (IOException e)
    {
        //执行从IOException恢复的操作
    }
    finally {
        //执行资源清理
        if (file != null) {
            file.Close();
        }
    }

2.自定义异常

C#的规范规定System.Exception是所有异常的基类,然后System.ApplicationException和System.SystemException直接从System.Exception派生,另外,System.ApplicationException是所有用户自定义异常的基类,System.SystemException是所有系统异常类的基类。
但这一规定并没有得到很好的执行,比如System.InvalidTimeZoneException直接派生于System.Exception类,像这种"不守规范"的异常类还有很多,所以说System.ApplicationException和System.SystemException类型没有什么特殊的含义了。
自定义异常建议直接从System.Exception派生,设计自己的异常通常是一件比较繁琐的事,因为从System.Exception派生异常都应该是序列化的。

/// <summary>
/// 定义一个泛型异常类,该类主要用于完成序列化操作
/// </summary>
/// <typeparam name="TExceptionArgs"></typeparam>
[Serializable]
public sealed class Exception<TExceptionArgs> : Exception
where TExceptionArgs : ExceptionArgs
{
private const String c_args = "Args";//用作(反)序列化的key
private readonly TExceptionArgs m_args = null;

public Exception(String Message = null, Exception InnerException = null):
    this(null,Message,InnerException) {
}
public Exception(TExceptionArgs m_args = null, String Message = null, Exception InnerException = null) :
    base(Message,InnerException){
    this.m_args = m_args;
}
/// <summary>
/// 该构造器用于反序列化,如果该类是密封的,那么该构造器应该是私有的。
/// 如果该类不是密封的,那么该构造器应该是受保护的。
/// </summary>
/// <param name="info"></param>
/// <param name="context"></param>
[SecurityPermissionAttribute(SecurityAction.Demand,SerializationFormatter=true)]
private Exception(SerializationInfo info, StreamingContext context):
    base(info,context)
{
    m_args = (TExceptionArgs)info.GetValue(c_args, typeof(TExceptionArgs));
}
/// <summary>
/// 该方法用于序列化
/// </summary>
/// <param name="info"></param>
/// <param name="context"></param>
[SecurityPermissionAttribute(SecurityAction.Demand,SerializationFormatter=true)]
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
    info.AddValue(c_args,m_args);
    base.GetObjectData(info,context);
}
public override string Message {
    get {
        String baseMsg = base.Message;
        return String.IsNullOrEmpty(m_args.Message) ? baseMsg : baseMsg + "("+m_args.Message+")";
    }
}
public override Boolean Equals(Object obj)
{
    Exception<TExceptionArgs> other = obj as Exception<TExceptionArgs>;
    if (other == null) {
        return false;
    }
    return Object.Equals(m_args, other.m_args) && base.Equals(obj);
}
public override int GetHashCode()
{
    return base.GetHashCode();
}
}
Exception<TExceptionArgs>.csc

相关文章:

  • 2021-06-01
  • 2021-09-25
  • 2022-12-23
  • 2021-11-26
  • 2021-11-08
  • 2021-07-13
  • 2021-12-21
  • 2021-08-08
猜你喜欢
  • 2022-01-07
  • 2021-05-28
  • 2022-12-23
  • 2021-12-21
  • 2022-12-23
  • 2021-08-04
相关资源
相似解决方案