C#学习笔记 异常处理

System.Exception类

C#中定义了很多异常类,C#的异常类都是System.Exception的子类。它派生了两个子类:SystemExceptionApplicationException。其中前者是系统定义的各种异常,后者则提供应用程序使用。
Exception的构造方法常用的有两个:

public Exception();
public Exception(string s);

第二个构造方法可以接受字符串参数传入的信息,该信息通常是对该例外所对应的错误的描述。Exception类有两个重要的属性:Message属性、StackTrace属性。
Message属性: 描述错误的可读文本。在创建异常对象过程中,可以将文本字符串传递给构造方法以描述该特定异常的详细信息。
StackTrace属性 发生异常时调用堆栈的状态。包括错误发生位置的堆栈跟踪、所有调用的方法和源文件中这些调用所在的行号。

系统定义的异常

如下表:
在这里插入图片描述
在这里插入图片描述

捕获和处理异常

C#中的异常处理机制可以概括成以下几个步骤:

  • ① C#程序的执行过程中如出现异常,会自动生成一个异常类对象,该异常对象将被提交给C#运行时的系统,这个过程称为抛出(throw)异常。抛出异常也可以有程序来强制的用throw语句来进行。
  • ② 当C#运行时系统接收到异常对象时,会寻找能处理这一异常的代码并把当前异常对象交给其处理,这一过程称为捕获(catch)异常。
  • ③ 如果C#运行时系统找不到可以捕获异常的方法,则运行时系统将终止,相应的C#程序也将退出。

1.抛出异常 throw

C#程序在运行时如果引发了一个可识别的错误,就会产生一个与该错误相对应的异常类的对象,这个过程称为异常的抛出。
(1)系统自动抛出的异常
所有的系统定义的运行异常都可以由系统自动抛出。
(2)语句抛出的异常
用户程序自定义的异常不可能依靠系统自动抛出,而必须借助于throw语句来定义何种情况算是产生了此类异常对应的错误,并且抛出这个异常类的新对象。格式为:

	throw 异常对象;

2.捕获异常 catch

当一个异常被抛出时,应该有专门的语句来接收这个被抛出的异常对象,这个过程称为捕获异常。当一个异常类的对象被捕捉或接收后,用户程序就会发生流程的跳转,系统终止当前的流程而跳转至专门的异常处理语句块,或者直接跳出当前程序并终止。

在C#程序中使用catch语句,其格式如下:

	try {
    
    
		语句组
	} catch(异常类名 异常形式参数名) {
    
    
		异常处理语句
	} catch(异常类名 异常形式参数名) {
    
    
		异常处理语句
	} finally {
    
    
		异常处理语句
	}

其中至少有一个catch语句或finally语句。
finally语句: finally语句为异常处理提供一个统一的出口,不论try代码块及catch块中是否发生了异常事件也不论出现任何语句(即使用returnthrow抛出异常),finally块中的语句都会被执行。

用户自定义异常类

创建用户自定义异常时,一般需要完成如下的工作:

  • ① 声明一个新的异常类,使之以ApplicationException类或其他某个已经存在的系统异常类或用户异常类为父类。
  • ② 为新的异常类定义属性和方法,或重载父类的属性和方法,使这些属性和方法能够体现该类所对应的错误的信息。

例如:

public class MyAppException : ApplicationException
{
    
    
	public MyAppException(string message) : base(message) {
    
     }
}

重抛异常及异常链接

系统中对于异常,可以进行捕获和处理,有时候不仅要处理,还要将此异常进一步传递给调用者,以便让调用者也能感受到这种异常。这时可以在catch语句块或finally语句块中采取以下三种方式:

  • ① 使用不带表达式的throw语句,将当前捕获的异常再次抛出。格式如下:
	throw;
  • ② 重新生成一个异常,并抛出,如:
	throw new Exception("some message");
  • ③ 重新生成并抛出一个新异常,该异常中包含了当前异常的信息,如
	throw new Exception("some message", e);

其中,最后一种方法比较好,因为它将当前异常的信息保留,并且向调用者返回了一个更有意义的信息。这种方式被称为“异常的链接”。如果相关的异常都采用这种方式,能够使上层的调用者逐步深入地找到相关的异常信息。
这种方式中,除了用到Exception类的MessageStackTrace属性和ToString() 方法外,还常用到InnerException属性。
InnerException是一个只读属性,它包含这个异常的“内部异常”。如果它不是null,就指出当前的异常是作为对另外一个异常的链接而被抛出。
为了对InnerException属性进行指定,必须使用以下构造方法:

	public Exception(string Message, Exception InnerException);

其中第二个参数指定了这个“内部异常”。如果是用户自定义的异常,也一般要提供一个构造方法,参数中能指定这个内部异常。

示例使用内部异常进行异常的链接:

using System;

public class DataHouse
{
    
    
	public static void FindData(long ID) {
    
    
		if (ID > 0 && ID < 1000)
			Console.WriteLine(ID);
		else
			throw new DataHouseException("已收到文件尾");
	}
}

public class BankATM
{
    
    
	public static void GetBalanceInfo(long ID) {
    
    
		try {
    
    
			DataHouse.FindData(ID);
		} catch (DataHouseException e) {
    
    

			throw new MyAppException("账号不存在", e);
		}
	}
}

public class DataHouseException : ApplicationException
{
    
    
	public DataHouseException(string message) : base(message) {
    
     }
}
public class MyAppException : ApplicationException
{
    
    
	public MyAppException(string message) : base(message) {
    
     }
	public MyAppException(string message, Exception inner) : base(message, inner) {
    
     }
}

class Program
{
    
    
	static void Main(string[] args) {
    
    
		Console.WriteLine("Hello World!");

		try {
    
    
			BankATM.GetBalanceInfo(12345L);
		} catch (Exception e) {
    
    
			Console.WriteLine("出现了异常: {0}", e.Message);
			Console.WriteLine("内部原因: {0}", e.InnerException.Message);
		}
	}
}

猜你喜欢

转载自blog.csdn.net/qq_45349225/article/details/114109201