初探C# 异常处理

一、基础

在C# 里,异常处理就是C# 为处理错误情况提供的一种机制。它为每种错误情况提供了定制的处理方式,并且把标识错误的代码与处理错误的代码分离开来。

对.NET类来说,一般的异常类 System.Exception 派生于 System.Object。还有许多定义好的异常类(如:System.SystemException、System.ApplicationException等),他们又派生于 System.Exception 类。其中System.ApplicationException 类是第三方定义的异常类,如果我们要自定义异常类,那么就应派生于它。

在代码中对异常进行处理,一般要使用三个代码块:

  • Try 块的代码是程序中可能出现错误的操作部分。
  • Catch 块的代码是用来处理各种错误的部分(可以有多个)。必须正确排列捕获异常的catch子句,范围小的Exception放在前面的catch。即如果Exception之间存在继承关系,就应把子类的Exception放在前面的catch子句中
  • Finally 块的代码用来清理资源或执行要在try块末尾执行的其他操作(可以省略)。且无论是否产生异常,Finally块都会执行。

二、异常处理

不管程序写得再好,异常都可能会发生,而程序也必须能够处理可能出现的错误。所以我们要站在异常一定可能会发生的角度来编写异常处理程序,应对程序有可能发生的错误建立一个良好的异常处理策略。

异 常产生的时候,我们想知道的是什么原因造成的错误以及错误的相关信息。我们可以根据实际情况抛出具体类型的异常,方便捕捉到异常时做出具体的处理。在编写 代码过程中,可以使用系统已定义的相关异常类以及自定义的异常类来实例化并抛出我们需要的异常。如一个不可能实现的接口,我们可以抛出 “System.NotSupportedExceptiion”的异常来告诉接口的调用者。

在 处理异常的时候,我们应该将可处理的具体异常分别在catch 块中做出相应处理,否则程序将终止运行。针对每一种异常,以不同方式处理,避免对所有异常做出一样的处理。并且在异常产生时,给用户一个友好的提示(普通 用户对异常的具体内容是不明白的,这就需要我们给出相关的简要信息和解决方案,或则告之联系管理员等。),并在可能的情况下给用户提供可能的选择(终止, 重试,忽略),让用户来决定程序的运行方向。同时,要将异常做日志记录。但不是所有异常都是必须记录的,比如一些可预料并且能让程序解决的错误我们就不需 要记录它。

记录异常我们可以采取如下一些方式:

  • 在文件中记录异常。便于技术人员查看所发生的异常,从而日后对程序进行改进。
  • 在数据库中记录异常。数据库支持查询,这样在后期就能够对异常进行分类查询等操作,便于查看与管理。
  • 在Eventlog中记录异常:能够远程操作,方便系统管理员监控所有计算机的异常。

除 了具体的、可预料到的异常外,还有未预料的异常。像这类异常是我们不愿意看到了,但发生了也只能暂时结束程序的运行,这里如果做好了日志就能为我们解决和 调试问题带来了方便。还有,要避免使用了try-catch但没有处理异常的情况,否则就相当于给异常放行(这种情况还不如根本就不去捕获它)。

处理完异常,我们还应该注意在finally块中释放相关资源、还原相关设置信息等收尾工作。

在做异常处理的时候,最好能在应用程序所有的入口处(事件处理函数,主函数,线程入口)使用try-catch。 但是不要在程序构造函数入口处添加try-catch,因为此处产生异常,它自己并没有能力来处理,因为它还没有构造完毕,只能再向外层抛出异常。

在 一般情况下使用异常机制来处理错误,能使整个程序的结构清晰、代码简单(标识错误的代码与处理错误代码分离),但我们也不能盲目使用异常。而且使用异常, 可能会在一定程度上影响到程序的性能(C#中使用异常一般不影响性能)。对于一些简单的、能够提前避免的错误,我们还是应该在try块外面及早做出处理。 如:

try
{
int x = y/z;
}
catch
{
// ...
}


if(z == 0)
{
Console.WriteLine("除数不能为零");
// ...
}
try
{
int x = y/z;
}
catch
{
// ...
}

附1:测试代码

Test01() 为一般嵌套异常处理

Test02() 为内层 catch 块中没有合适的处理程序存在的嵌套异常处理

Test03() 为在 catch 块中抛出异常的情况(当前处理不了该异常,那么把它再抛出)

using System;
using System.IO;

namespace ConsoleApp
{
class App
{
// 自定义异常类
public class MyException : ApplicationException
{
public MyException(string message) : base(message)
{
}

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

// 实例化异常对象,并抛出异常
private static void ThrowException()
{
//throw new NotImplementedException();
throw new FileNotFoundException();
//throw new IOException();
}

public static void Main()
{
Console.Write(">>> Test01" + (char)10);
Test01();

Console.Write(">>> Test02" + (char)10);
Test02();

Console.Write(">>> Test03" + (char)10);
Test03();
}

private static void Test01()
{
try
{
try
{
throw new MyException("My error.");
}
catch(MyException ex)
{
Console.WriteLine("MyException: " + ex.Message);
}
catch
{
Console.WriteLine("Unexpected error!");
}
finally
{
Console.WriteLine(" --- inside finally ---");
}

ThrowException();
}
catch(IOException ex)
{
Console.WriteLine("IOException: " + ex.Message);
}
catch(ApplicationException ex)
{
Console.WriteLine("ApplicationException: " + ex.Message);
}
catch(SystemException ex)
{
Console.WriteLine("SystemException: " + ex.Message);
}
catch
{
Console.WriteLine("Unexpected error!");
}
finally
{
Console.WriteLine(" --- outside finally ---");
}

Console.ReadLine();
}

private static void Test02()
{
try
{
try
{
// 抛出自定义异常 MyException ,
// 但内层 catch 块中没有合适的处理程序存在
throw new MyException("My error.");
}
catch(IOException ex)
{
Console.WriteLine("IOException: " + ex.Message);
}
finally
{
Console.WriteLine(" --- inside finally ---");
}
}
catch(MyException ex)
{
Console.WriteLine("MyException: " + ex.Message);
}
catch(Exception ex)
{
Console.WriteLine("Exception: " + ex.Message);
}
finally
{
Console.WriteLine(" --- outside finally ---");
}

Console.ReadLine();
}

private static void Test03()
{
try
{
try
{
throw new IOException();
}
catch(IOException ex)
{
// 在 catch 块中抛出异常
throw new MyException("My error." + ex.Message);
}
catch(Exception ex)
{
Console.WriteLine("Exception: " + ex.Message);
}
finally
{
Console.WriteLine(" --- inside finally ---");
}
}
catch(Exception ex)
{
Console.WriteLine("Exception: " + ex.Message);
}
finally
{
Console.WriteLine(" --- outside finally ---");
}

Console.ReadLine();
}
}
}

附2:全局异常处理、多线程中的异常处理

将 全局异常处理函数的委托加入到 Application.ThreadException 中,实现全局异常处理,但它只能处理主线程中未捕获的异常。在多线程异常处理时,工作线程/辅线程中产生异常,可以把它转给主线程来完成异常处理。如果线 程之间不通知,是无法直接捕捉异常的。若没有去处理工作线程/辅线程中产生的异常,该异常将会“消失”掉。

为 什么要把异常处理都交给主线程去做呢?举个例子:在WinForm里我们使用多线程来处理界面元素,一旦有异常发生就将异常消息显示出来。那么,是直接在 异常发生后就MessageBox,还是将消息交给MainUI来统一显示?试想一下,程序要是复杂点或是有多个界面采用多线程来显示界面元素,那么采用 前者,我们就算知道了异常的详细信息,但可能还是很难找到究竟是哪里出了问题。而通过MainUI来显示,情况就要好很多了,尤其是还设计到其他东西的时 候(如:多语言环境)。当然,这个例子只是很小的一个方面。下面就来看怎么来实现:

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Threading;

namespace ThreadApp
{
public class frmMain : System.Windows.Forms.Form
{
private System.Windows.Forms.Button btRun;
///
/// 必需的设计器变量。
///
private System.ComponentModel.Container components = null;

public delegate void WorkerThreadExceptionHandlerDelegate(Exception e);
void WorkerThreadExceptionHandler(Exception e)
{
this.Text = "Disposed.";
MainUIThreadExceptionHandler(this, new System.Threading.ThreadExceptionEventArgs(e));
}

public frmMain()
{
InitializeComponent();
}

///
/// 清理所有正在使用的资源。
///
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}

#region Windows 窗体设计器生成的代码
///
/// 设计器支持所需的方法 - 不要使用代码编辑器修改
/// 此方法的内容。
///
private void InitializeComponent()
{
this.btRun = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// btRun
//
this.btRun.Location = new System.Drawing.Point(72, 24);
this.btRun.Name = "btRun";
this.btRun.TabIndex = 0;
this.btRun.Text = "Run";
this.btRun.Click += new System.EventHandler(this.btRun_Click);
//
// frmMain
//
this.AutoScaleBaseSize = new System.Drawing.Size(6, 14);
this.ClientSize = new System.Drawing.Size(224, 69);
this.Controls.Add(this.btRun);
this.Name = "frmMain";
this.Text = "ThreadApp";
this.ResumeLayout(false);

}
#endregion

///
/// 应用程序的主入口点。
///
[STAThread]
static void Main()
{
Application.ThreadException += new ThreadExceptionEventHandler(MainUIThreadExceptionHandler);
Application.Run(new frmMain());
}

public static void MainUIThreadExceptionHandler(Exception e)
{
MainUIThreadExceptionHandler(null, new System.Threading.ThreadExceptionEventArgs(e));
}

public static void MainUIThreadExceptionHandler(object sender, ThreadExceptionEventArgs t)
{
MessageBox.Show(t.Exception.Message,"Exception",
MessageBoxButtons.OK,
MessageBoxIcon.Warning);
}


private void ThrowException()
{
throw new NotImplementedException();
}

private void Run()
{
try
{
this.Text = "Waiting..."; //[错误]这里在2.0里是编译不通过的。因为它已经违背了我们的原则——不要跨线程操作(当前线程对界面线程的元素进行了操所)
Thread.Sleep(2000);
this.Text = "Throw Exception...";
ThrowException();
this.Text = "Finished"; //[错误](同上)
}
catch(Exception e)
{

// 如果涉及到多线程的互操作时,
// 可以运用BeginInvoke方法来实现多线程间的互访问。
this.BeginInvoke(
new WorkerThreadExceptionHandlerDelegate(
WorkerThreadExceptionHandler),
new object[]{e}); }
}

private void btRun_Click(object sender, System.EventArgs e)
{
ThreadStart ts = new ThreadStart(Run);
Thread t = new Thread(ts);
t.Start();

//throw new NotSupportedException();
}
}
}

ros1 ubuntu22.04 安装教程 ROS1 ubuntu22.04 安装教程 阅读详情

相关推荐

Oracle迁移至华为GaussDB SQL语法和存储过程转换

在将Oracle数据库迁移至GaussDB时,SQL语法和存储过程的转换是确保应用程序正常运行和数据完整性的关键环节。由于两者在数据类型、函数、过程语言等方面存在差异,必须系统化地进行转换和测试。正则表达式脚本:批量替换常见的语法差异。SQL解析工具:解析SQL脚本,生成GaussDB兼容的语法。代码审查工具:自动检查转换后的代码,确保语法和逻辑正确。将Oracle迁移至GaussDB涉及到SQL语法和存储过程的全面转换。通过系统化的转换步骤、使用合适的工具并结合手动调整,可以确保迁移过程的顺利进行。

weixin_38428874的博客 2399

文件操作中出现system.notsupportedexception异常

偶然的用了如下代码 string sourceDoc = ""; bool isExists = File.Exists(sourceDoc); 此时isExists变量得到的值为false; 仔细查看了变量sourceDoc的值,确定路径已经文件名都没错。 打断点在即时窗口中调试 以如下形式调用 : File.Exists(sourceDoc) 返回值是false,同时还显示 “

u011623102的专栏 2万+

AMG8833红外测温实战:在STM32F103上做个简易人体感应与温度报警器

本文详细介绍了如何在STM32F103上使用AMG8833红外测温传感器构建人体感应与温度报警系统。通过硬件连接方案、驱动代码开发、人体检测算法实现及报警系统设计,展示了如何利用8x8红外温度矩阵实现智能监测功能。文章包含实用的初始化流程、温度数据读取优化和低功耗策略,为创客项目提供完整解决方案。

weixin_33725239的博客 394

Silverlight访问Web Service报"System.Security.SecurityException: 安全性错误"的处理

好几次了,执行的好好的Silverlight项目调用Web Service时报"System.Security.SecurityException: 安全性错误",如下图所示: 因为这几天只是学习、测试Silverlight的功能,并没有作什么正式的项目,所以每次看到这个就直接重新建一个工程,今天真的不耐烦了,上网找了下原因,大概是Silverlight跨域访问的权限问题,需要在Silverli...

weixin_34342207的博客 212

从一只龙虾到一支团队:OpenClaw 单 Bot 多 Agent 配置实践

单 Bot 多 Agent只有一个对外的聊天入口(飞书 Bot)内部有多个独立的 AI Agent,各司其职主 Agent(总指挥)负责接收任务并分配给子 Agent子 Agent 完成任务后将结果返回给主 Agent角色Agent ID职责使用场景🎯 总指挥main-agent统筹协调,任务分发接收所有用户请求✍️ 笔杆子内容创作公众号、博客、小红书🔬 参谋canmou深度研究竞品分析、市场调研📋 运营官operations运营管理邮件、日历、社交媒体。

Maynor的博客 1082

SPI 总线信号完整性与时序一致性测试

SPI总线测试的核心目标是验证其电气与时序行为是否满足芯片规格要求,确保通信可靠性

硬核科技 330

C#异常处理初探

try catch finally简单的三个关键字,其处理流程却较为复杂,下面先分各种情况讨论,最后得出结论,并提出使用建议。 1 没有发生异常的情况 class Program { static void Main(string[] args)

smstong的成长轨迹 3231

java零基础从入门到精通(全)

目录前言1. 入门知识1.1 java体系1.2 JDK/JRE/JVM区别1.3 编译与运行理解1.4 类体函数细节2. 标识符 前言 java优势 健壮性(JVM(C++语言写的一个虚拟的计算机)、GC(垃圾回收机制)) 多线程并发 可移植性/跨平台 1. 入门知识 1.1 java体系 JavaSE:标准版 JavaEE:企业版 JavaME:微型版 1.2 JDK/JRE/JVM区别 JVM是不能独立安装的。 JRE和JDK都是可以独立安装的 层层嵌套,jvm包括jdk,jdk包括jre

码农研究僧的博客 6万+

MFC 异常处理设置

最近从c#转MFC,看着同事们写的代码居然一个try {}catch{}都没有,心里就纳闷了....       刚开始随便弄了个简单的异常try catch了一下,发现居然没能捕捉抛出异常,程序直接挂了....摸索了好久,才发傻瓜式的C#中try catch在MFC中运用是那么的悲催~      MFC中要想能try catch必须启用C++异常:工程属性>配置属性>C/C++>代码生成>启

893

AD9361功能介绍和使用

AD9361使用分数分频锁相环(PLL)来产生发射机和接收机本地振荡器(LO)频率和BB PLL。BB PLL 可用于数据转换、数字滤波器和 |/O 端口。PLL的参考时钟可以由外部振荡器或外部晶体(XO)和数字可编程片内可变电容提供,电容微调产生参考时钟频率,XO和微调电容的组合统称为DCXO。有多个天线输入的分集系统。接收链数据首先经过低噪声放大器(LNA),然后是同相(1)和正交(Q)放大器,混频器和频带整形滤波器,可将接收到的信号下变频为基带以进行数字化。时分双工(TDD)和频分双工(FDD)。。。

wangjie36的博客 1万+

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

【C#基础】C# 异常处理操作

编程语言 C# 异常处理操作知识点介绍。

好学若饥,谦卑若愚。 6635

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

C# 异常处理

异常处理机制为开发者提供了一种有效的方式,能够将程序的控制权从出现问题的部分合理地转移到其他部分,确保程序在遇到意外情况时依然能够保持相对稳定的运行状态,或者至少能够以一种可控的方式终止并给出相应提示。C# 的异常处理建立在四个至关重要的关键词之上,它们分别是 try、catch、finally 和 throw,各自承担着不同且关键的职责,共同构建起了完善的异常处理体系。除了使用系统预定义的异常类来处理常见的异常情况外,开发者还可以根据实际业务需求定义自己的异常。tryelse。

2401_83367969的博客 2453

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

C#:异常处理

C#异常处理总结及简单实例 一、异常处理的理解? 异常处理是指程序在运行过程中,发生错误会导致程序退出,这种错误,就叫做异常。 错误的出现并不总是程序员的原因,比如:连接数据库停电了,操作文件文件没了,权限不足,除数是0,使用对象是对象为null等。不处理错误程序没法继续执行。 .NET为我们把发现错误(try)的代码与处理错误(catch)的代码分离开来。 二、异常处理如何操作? C...

icnhh的专栏 2674

C# 异常处理 详解

C# 异常处理 详解

鲤籽鲲的博客 1282

C#异常处理

异常是在程序执行期间出现的问题。C# 中的异常是对程序运行时出现的特殊情况的一种响应,比如尝试除以零。 异常提供了一种把程序控制权从某个部分转移到另一个部分的方式。 C# 异常处理时建立在四个关键词之上的:try、catch、finally和throw。 try:一个 try 块标识了一个将被激活的特定的异常的代码块。后跟一个或多个 catch 块。 catch:程序通过异常处理程序捕获异常。catch 关键字表示异常的捕获。 finally:finally 块用于执行给定的语句,不管异常是否..

荒唐的博客 2987

C#中的异常处理

一、 异常的概念 C#语言的异常处理功能在程序运行期间发生的任何意外或异常情况。异常处理功能使用Try、catch和finally关键字来尝试执行可能失败的操作、在确定合理的情况下处理故障、以及在事后清理资源。 二、异常类 在BCL中定义了很多类,每一个类代表一个指定异常类型。当一个异常发生时,CLR: 1、 创建了该类型的异常对象; 2、 寻找适当的catch 子句来处理它; .NET Framework 类库中的所有异常都派生于 Exception 类,异常包括系统异常和应用异常。 默认的所有系统异常派

saoang的博客 3974
上一篇: C#中使用try catch对系统性能的影响和处理机制的学习总结!
下一篇: C#制作屏幕保护的方法 函数
flyhighwl
博客等级 码龄15年 8粉丝 139原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值