C#基础7
C#异常处理
异常时在程序执行期间出现的问题。C#中的异常时对程序运行时出现的特殊情况的一种响应,比如尝试除以零。
异常提供了一种吧程序控制权从某个部分转移到另一个部分的方式。C#异常处理时建立在四个关键字之上:Try、catch、finally、throw
Try:一个try块表示了一个将被激活的特定的异常的代码块。后跟一个或多个catch块。
catch:程序通过异常处理程序捕获异常。catch关键字表示异常的捕获。
finally:finally块用于执行给定的语句,不管异常是否被抛出都会执行。例如,如果您打开一个文件,不管是否出现异常文件都要被关闭。
throw:当问题出现时,程序抛出一个异常。使用throw关键字来完成。
try块(保护区): 这里放置的是核心程序语句。即那些你认为可能会在运行期间发生错误的代码(例如文件读写、网络请求、数学计算等)。catch块(处理区): 这里放置的是错误处理语句。当try块中的代码抛出异常时,程序流程会立即跳转到这里。你可以在这里记录错误日志、提示用户或进行补救措施。finally块(清理区): 无论是否发生异常,这里的代码都会执行。通常用于释放资源(如关闭文件流、断开数据库连接),确保系统资源不泄露。
C#中的异常类
C#异常是使用类来表示的。C#中的异常类主要是直接或间接地派生于System.Exception类。System.ApplicationException和System.SystemException类是派生于System.Exception类的异常类。
System.ApplicationException类支持由应用程序生成的异常。所以程序员定义的异常都应派生自该类。
System.SystemException类是所有预定义的系统异常的基类。
下表列出了一些派生自System.SystemException类的预定义的异常类:
|
异常类 |
描述 |
|---|---|
|
System.IO.IOException |
处理 I/O 错误。 |
|
System.IndexOutOfRangeException |
处理当方法指向超出范围的数组索引时生成的错误。 |
|
System.ArrayTypeMismatchException |
处理当数组类型不匹配时生成的错误。 |
|
System.NullReferenceException |
处理当依从一个空对象时生成的错误。 |
|
System.DivideByZeroException |
处理当除以零时生成的错误。 |
|
System.InvalidCastException |
处理在类型转换期间生成的错误。 |
|
System.OutOfMemoryException |
处理空闲内存不足生成的错误。 |
|
System.StackOverflowException |
处理栈溢出生成的错误。 |
异常处理
C#以try和catch块的形式提供了一种结构化的异常处理方案。使用这些块,把核心程序语句与错误处理语句分离开。
这些错误处理块是使用try、catch和finally关键字实现的。下面是一个当除以零时抛出异常的实例:
using System;
namespace ErrorHandlingApplication
{
class DivNumbers
{
int result;
DivNumbers()
{
result = 0;
}
public void division(int num1, int num2)
{
try
{
result = num1 / num2;
}
catch (DivideByZeroException e)
{
Console.WriteLine("Exception caught: {0}", e);
}
finally
{
Console.WriteLine("Result: {0}", result);
}
}
static void Main(string[] args)
{
DivNumbers d = new DivNumbers();
d.division(25, 0);
Console.ReadKey();
}
}
}
看着个
try { //
--- 核心程序语句 ---
// 这里放正常的业务逻辑
int result = 10 / 0; // 可能会发生除零异常
Console.WriteLine("计算结果: " + result);
}
catch (DivideByZeroException ex)
{
// --- 错误处理语句 ---
// 专门处理除零错误的逻辑
Console.WriteLine("发生错误:除数不能为零。");
Console.WriteLine("错误详情: " + ex.Message);
}
catch (Exception ex)
{
// 处理其他未知异常
Console.WriteLine("发生了其他未知错误。");
}
finally
{
// --- 资源清理 ---
// 无论是否出错,都会执行
Console.WriteLine("程序执行完毕,资源已释放。");
}
创建用户自定义异常
您也可以定义自己的异常。用户自定义的异常类是派生自ApplicationException类。下面的实例演示了这点:
using System;
namespace UserDefinedException
{
class TestTemperature
{
static void Main(string[] args)
{
Temperature temp = new Temperature();
try
{
temp.showTemp();
}
catch(TempIsZeroException e)
{
Console.WriteLine("TempIsZeroException: {0}", e.Message);
}
Console.ReadKey();
}
}
}
public class TempIsZeroException: ApplicationException
{
public TempIsZeroException(string message): base(message)
{
}
}
public class Temperature
{
int temperature = 0;
public void showTemp()
{
if(temperature == 0)
{
throw (new TempIsZeroException("Zero Temperature found"));
}
else
{
Console.WriteLine("Temperature: {0}", temperature);
}
}
}
当上面的代码被编译和执行时,它会产生下列结果:
TempIsZeroException: Zero Temperature found
抛出对象
如果异常是直接或间接派生自System.Exception类,您可以抛出一个对象。您可以在catch块中使用throw语句来抛出当前的对象,如下所示:
Catch(Exception e)
{
...
Throw e
}
虽然这种分离机制很好,但在使用时请注意以下几点:
- 只捕获你能处理的异常: 不要随意捕获所有异常然后忽略它(即空的
catch块),这会导致程序在出错时“静默失败”,难以排查问题。 - 具体的异常在前: 如果你有多个
catch块,请将最具体的异常类型(如DivideByZeroException)放在前面,将通用的异常类型(如Exception)放在最后。 - 保留堆栈信息: 如果你在
catch块中处理完错误后决定重新抛出异常,请使用throw;而不是throw ex;,这样可以保留原始的错误堆栈信息,方便调试。
| 场景 | 代码写法 | 结果 |
|---|---|---|
| 主动报错 | throw new Exception("..."); |
创建并抛出新异常 |
| 保留现场 | catch { ... throw; } |
重新抛出原异常,保留堆栈信息 |
| 重置现场 | catch { ... throw ex; } |
重新抛出,丢失原始堆栈信息 (应避免) |
何时应该使用 throw?
根据最佳实践,你应该在以下情况引发异常:
- 方法无法完成其定义的功能: 例如参数为 null 或格式错误(抛出
ArgumentException)。 - 对象状态不支持当前操作: 例如尝试写入一个只读文件(抛出
InvalidOperationException)。 - 不要将异常作为控制流程的常规手段(例如用异常来代替
if判断循环结束),这会严重影响性能。
更多推荐

所有评论(0)