学习c#的第十七天

目录

C# 异常处理

异常的原因

System.Exception 类

如何处理异常

常见的异常类

throw 语句

throw 表达式

try 语句

try-catch 语句

try-finally 语句

try-catch-finally 语句

when 异常筛选器

异步和迭代器方法中的异常


C# 异常处理

C # 中的异常提供了结构化、统一和类型安全的方式来处理系统级别和应用程序级别的错误条件。 C # 中的异常机制与 c + + 中的异常机制非常相似,但有几个重要的区别:

  • 在 c # 中,所有异常必须由派生自的类类型的实例表示 System.Exception 。 在 c + + 中,任何类型的任何值都可以用来表示异常。
  • 在 c # 中,可以使用 try 语句 (finally 块) 来编写在正常执行和异常情况下执行的终止代码。 此类代码难以用 c + + 编写,无需复制代码。
  • 在 c # 中,系统级别的异常(如溢出、被零除和空引用)具有定义完善的异常类,并且与应用程序级别的错误条件是同等的。

异常的原因

可以通过两种不同的方法引发异常。

  • throw Throw 语句 (的语句) 会立即、无条件地引发异常。 控件永远不会到达紧跟的语句后面的语句 throw 。
  • 在处理 c # 语句和表达式过程中出现的某些异常情况会在某些情况下导致无法正常完成操作时引发异常。 例如,如果分母为零,则 (除法运算符) 整数除法运算将引发 System.DivideByZeroException 。

System.Exception 类

System.Exception类是所有异常的基类型。 此类具有一些例外的属性,这些属性是所有异常都共享的:

  • Message 是类型的只读属性 string ,它包含对异常原因的可读说明。
  • InnerException 是类型的只读属性 Exception 。 如果其值不为 null,则表示导致当前异常的异常,即在处理的 catch 块中引发当前异常 InnerException 。 否则,其值为 null,表示此异常不是由其他异常导致的。 以这种方式链接在一起的异常对象的数量可能是任意的。

可以在对的实例构造函数的调用中指定这些属性的值 System.Exception 。

如何处理异常

异常由 try语句处理。
发生异常时,系统会搜索 catch 可处理异常的最近子句,如异常的运行时类型所确定。 首先,搜索当前方法,查找词法上的封闭 try 语句,并按顺序考虑 try 语句的关联的 catch 子句。 如果此操作失败,则会在调用当前方法的方法中搜索一个词法封闭 try 语句,该语句将调用的点包围到当前方法。 此搜索将继续执行 catch ,直到找到可处理当前异常的子句为止,方法是将与所引发的异常的运行时类型的异常类命名为相同的类或基类。 catch不命名异常类的子句可处理任何异常。
找到匹配的 catch 子句后,系统准备将控制转移到 catch 子句的第一条语句。 在开始执行 catch 子句之前,系统首先会按顺序执行 finally 与尝试语句相关联的、与捕获异常的子句更嵌套的所有子句。
如果未找到匹配的 catch 子句,则会出现以下两种情况之一:

  • 如果在 (静态构造函数) 或静态字段初始值设定项的情况下搜索匹配的 catch 子句,则 System.TypeInitializationException 会在触发静态构造函数调用的那一点引发。 的内部异常 System.TypeInitializationException 包含最初引发的异常。
  • 如果对匹配的 catch 子句的搜索到达最初启动线程的代码,则终止线程的执行。 此类终止的影响是由实现定义的。

在析构函数执行过程中发生的异常值得特别提。 如果在析构函数执行过程中发生异常,且未捕获该异常,则将终止该析构函数的执行,并且如果调用了任何) ,则将 (基类的析构函数。 如果在类型) 的情况下没有 (的基类 object ,或者如果没有基类析构函数,则放弃该异常。

常见的异常类

异常类描述
System.IO.IOException处理 I/O 错误。
System.IndexOutOfRangeException处理当方法指向超出范围的数组索引时生成的错误。
System.ArrayTypeMismatchException处理当数组类型不匹配时生成的错误。
System.NullReferenceException处理当依从一个空对象时生成的错误。
System.DivideByZeroException处理当除以零时生成的错误。
System.InvalidCastException处理在类型转换期间生成的错误。
System.OutOfMemoryException处理空闲内存不足生成的错误。
System.StackOverflowException处理栈溢出生成的错误。

throw 语句

throw 语句引发异常:

if (shapeAmount <= 0)
{throw new ArgumentOutOfRangeException(nameof(shapeAmount), "Amount of shapes must be positive.");
}

在 throw e; 语句中,表达式 e 的结果必须隐式转换为 System.Exception。

可以使用内置异常类,例如 ArgumentOutOfRangeException 或 InvalidOperationException。 .NET 还提供了在某些情况下引发异常的帮助程序方法:ArgumentNullException.ThrowIfNull 和 ArgumentException.ThrowIfNullOrEmpty。 还可以定义自己的派生自 System.Exception 的异常类。 有关详细信息,请参阅创建和引发异常。

在 catch 块内,可以使用 throw; 语句重新引发由 catch 块处理的异常:

try
{ProcessShapes(shapeAmount);
}
catch (Exception e)
{LogError(e, "Shape processing failed.");throw;
}

注意:throw; 保留异常的原始堆栈跟踪,该跟踪存储在 Exception.StackTrace 属性中。 与此相反,throw e; 更新 e 的 StackTrace 属性。

引发异常时,公共语言运行时 (CLR) 将查找可以处理此异常的 catch 块。 如果当前执行的方法不包含此类 catch 块,则 CLR 查看调用了当前方法的方法,并以此类推遍历调用堆栈。 如果未找到 catch 块,CLR 将终止正在执行的线程。 有关详细信息,请参阅 C# 语言规范的如何处理异常部分。

以下是一个简单的例子,演示了如何使用throw语句抛出一个自定义的异常:

using System;namespace ExceptionHandling
{class Program{static void Main(string[] args){try{int divisor = 0;if (divisor == 0){throw new DivideByZeroException("除数不能为零!");}else{int result = 10 / divisor;Console.WriteLine("结果: " + result);}}catch (DivideByZeroException e){Console.WriteLine("捕获到异常: " + e.Message);}Console.ReadKey();}}
}

在这个示例中,当divisor的值为0时,我们手动抛出了一个DivideByZeroException异常。在catch块中,我们捕获这个异常并输出异常信息。 

throw 表达式

还可以将 throw 用作表达式。 这在很多情况下可能很方便,包括:

1、条件运算符。以下示例使用 throw 表达式在传递的数组 args 为空时引发ArgumentException:

string first = args.Length >= 1 ? args[0]: throw new ArgumentException("Please supply at least one argument.");

 2、null 合并运算符。 以下示例使用 throw 表达式在要分配给属性的字符串为 null 时引发ArgumentNullException:

public string Name
{get => name;set => name = value ??throw new ArgumentNullException(paramName: nameof(value), message: "Name cannot be null");
}

3、expression-bodied lambda 或方法。 以下示例使用 throw 表达式引发 InvalidCastException,以指示不支持转换为 DateTime 值:

DateTime ToDateTime(IFormatProvider provider) =>throw new InvalidCastException("Conversion to a DateTime is not supported.");

try 语句

可以通过以下任何形式使用 try 语句:try-catch - 处理在 try 块内执行代码期间可能发生的异常,try-finally - 指定在控件离开 try 块时执行的代码,以及 try-catch-finally - 作为上述两种形式的组合。

try-catch 语句

使用 try-catch 语句处理在执行代码块期间可能发生的异常。 将代码置于 try 块中可能发生异常的位置。 使用 catch 子句指定要在相应的 catch 块中处理的异常的基类型:

try
{var result = Process(-3, 4);Console.WriteLine($"Processing succeeded: {result}");
}
catch (ArgumentException e)
{Console.WriteLine($"Processing failed: {e.Message}");
}

可以提供多个 catch 子句:

try
{var result = await ProcessAsync(-3, 4, cancellationToken);Console.WriteLine($"Processing succeeded: {result}");
}
catch (ArgumentException e)
{Console.WriteLine($"Processing failed: {e.Message}");
}
catch (OperationCanceledException)
{Console.WriteLine("Processing is cancelled.");
}

发生异常时,将从上到下按指定顺序检查 catch 子句。 对于任何引发的异常,最多只执行一个 catch 块。 如前面的示例所示,可以省略异常变量的声明,并在 catch 子句中仅指定异常类型。 没有任何指定异常类型的 catch 子句与任何异常匹配,如果存在,则必须是最后一个 catch 子句。

如果要重新引发捕获的异常,请使用 throw 语句,如以下示例所示:

try
{var result = Process(-3, 4);Console.WriteLine($"Processing succeeded: {result}");
}
catch (Exception e)
{LogError(e, "Processing failed.");throw;
}

注意:throw; 保留异常的原始堆栈跟踪,该跟踪存储在 Exception.StackTrace 属性中。 与此相反,throw e; 更新 e 的 StackTrace 属性。

try-finally 语句

在C#中,try-finally语句用于确保无论是否发生异常,某些代码块都会得到执行。try块中的代码用于包含可能引发异常的逻辑,而finally块中的代码则始终会在try块中的代码执行完毕后被执行,无论是否发生了异常。

下面是一个简单的示例,演示了try-finally语句的用法:

using System;class Program
{static void Main(){try{Console.WriteLine("Try块:执行一些可能引发异常的操作。");throw new Exception("出了问题");}finally{Console.WriteLine("最后一块:清理和释放资源。");}}
}

在这个示例中,无论try块中抛出了异常,finally块中的代码总是会得到执行。这使得finally块非常适合用于资源释放、清理或者确保某些必要的操作得到执行。

需要注意的是,如果在try块中抛出了异常,并且该异常在catch块中得到处理,finally块仍然会在catch块执行完毕后被执行。

注意:当资源类型实现 IDisposable 或 IAsyncDisposable 接口时,请考虑 using 语句。 using 语句可确保在控件离开 using 语句时释放获取的资源。 编译器将 using 语句转换为 try-finally 语句。

 在几乎所有情况下,都会执行 finally 块。 未执行 finally 块的唯一情况涉及立即终止程序。 例如,由于 Environment.FailFast 调用或 OverflowException 或 InvalidProgramException 异常,可能会发生此类终止。 大多数操作系统在停止和卸载进程的过程中执行合理的资源清理。

try-catch-finally 语句

在C#中,try-catch-finally语句用于处理可能引发异常的代码块,并提供对异常的处理逻辑和资源清理的机会。

try块用于包含可能引发异常的代码,如果在try块中抛出了异常,程序会跳转到匹配的catch块进行异常处理。catch块可以捕获特定类型的异常并执行相应的处理逻辑。一个try块可以有多个catch块,每个catch块可以处理不同类型的异常。

finally块用于包含在try块中抛出异常或正常执行完成后都必须执行的代码。finally块中的代码总是会在try块的代码执行完毕后被执行,无论是否发生了异常。

以下是一个示例,演示了try-catch-finally语句的用法:

using System;class Program
{static void Main(){try{Console.WriteLine("Try块:执行一些可能引发异常的操作。");throw new Exception("出了问题");}catch (Exception e){Console.WriteLine($"Catch块:捕获到异常- {e.Message}");}finally{Console.WriteLine("最后一块:清理和释放资源。");}}
}

在这个示例中,我们在try块中抛出了一个异常,然后在catch块中捕获并处理该异常。无论是否发生了异常,finally块中的代码都会得到执行,用于进行资源清理等操作。

需要注意的是,catch块是可选的,你可以只使用try-finally语句来进行资源清理,而不处理异常。

when 异常筛选器

除了异常类型之外,还可以指定异常筛选器,该筛选器进一步检查异常并确定相应的 catch 块是否处理该异常。 异常筛选器是遵循 when 关键字的布尔表达式,如以下示例所示:

using System;namespace ExceptionHandling
{class Program{static void Main(string[] args){try{int[] numbers = { 1, 2 };Console.WriteLine(numbers[5]); // 这里会抛出 IndexOutOfRangeException}catch (Exception e) when (e is IndexOutOfRangeException){Console.WriteLine("捕获到数组越界异常,并且满足附加条件!");}catch (Exception e){Console.WriteLine("捕获到其他异常:" + e.Message);}Console.ReadKey();}}
}

在这个示例中,当访问数组越界时会抛出IndexOutOfRangeException异常。在第一个catch块中,我们使用when关键字来附加一个条件,即只有当捕获到的异常是IndexOutOfRangeException并且满足附加条件时,才会执行这个catch块。

注意:

可以为相同异常类型提供若干 catch 子句,如果它们通过异常筛选器区分。 其中一个子句可能没有异常筛选器。 如果存在此类子句,则它必须是指定该异常类型的最后一个子句。

如果 catch 子句具有异常筛选器,则可以指定与 catch 子句之后出现的异常类型相同或小于派生的异常类型。 例如,如果存在异常筛选器,则 catch (Exception e) 子句不需要是最后一个子句。

异步和迭代器方法中的异常

如果异步函数中发生异常,则等待函数的结果时,它会传播到函数的调用方,如以下示例所示:

using System;
using System.Collections.Generic;class Program
{static void Main(string[] args){try{foreach (var item in GenerateSequence()){Console.WriteLine(item);}}catch (Exception ex){Console.WriteLine("捕获到异常:" + ex.Message);}Console.ReadKey();}static IEnumerable<int> GenerateSequence(){yield return 1;yield return 2;throw new Exception("发生了异常!");yield return 3; // 永远不会执行到这里}
}

在这个示例中,GenerateSequence()是一个迭代器方法,它生成一个整数序列。在迭代过程中,我们抛出了一个异常。当迭代器前进到下一个元素时,异常被传播到调用方。在Main()方法中,我们使用foreach循环迭代序列,并使用try-catch块捕获异常。

请注意,当异常被捕获后,迭代器的后续元素将不会被生成,因为迭代器方法已经退出。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/145578.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C语言调用【Python3】

一、搭建编译环境 终端查询系统及软件版本dpkg -l 列出所有已安装的软件包 二、C语言中调用Python 使用 GCC编译并链接 Python 3.10 的共享库如何在C中获取和修改 sys.path 三、C语言调用无参python函数 四、C语言调用有参python函数 一、搭建编译环境 通过C语言调用Pyth…

关于FreeRTOS函数xSemaphoreGiveFromISR卡死的问题

0. 概述 关于FreeRTOS函数xSemaphoreGiveFromISR卡死的问题 1. 遇到的问题 在使用FreeRTOS调试激光雷达检测面积的项目的时候&#xff0c;遇到一个现象&#xff1a;在新加了一个线程之后&#xff0c;把程序下载到板子之后程序不会运行&#xff08;实际上已经运行了&#xff…

【C语法学习】26 - strcat()函数

文章目录 1 函数原型2 参数3 返回值4 使用说明5 示例5.1 示例1 1 函数原型 strcat()&#xff1a;将src指向的字符串拼接在dest指向的字符串末尾&#xff0c;函数原型如下&#xff1a; char *strcat(char *dest, const char *src);2 参数 strcat()函数有两个参数src和dest&am…

uniapp插件开发

安装android studio&#xff1a;安装目录下bin下的此文件&#xff0c;是用来修改分配给android studio的占用内存。 Android 11足够用。 创建新项目&#xff1a; 目录结构介绍&#xff1a; UI组件介绍&#xff1a;在设计程序界面时可以使用可视化拖拽的方式&#xff0c;没有必要…

vue3中使用reactive定义的变量响应式丢失问题(大坑!!!)

前言 在Vue 3中&#xff0c;可以使用reactive函数将普通JavaScript对象转换为响应式对象&#xff0c;这样当对象的属性发生变化时&#xff0c;就会自动更新相应的UI。 但是请注意以下情况可能会丢失数据的响应式&#xff1a; 响应式丢失的情况&#xff1a; 1、对使用reactiv…

被 Next.js 的环境变量给坑了一把...

最近在使用 Next.js 时遇到了一个问题&#xff0c;最后原因竟是 .env 取值问题&#xff0c;为这个问题花费了数小时的时间&#xff0c;希望看到这篇文章的朋友&#xff0c;如果遇到类似问题&#xff0c;不要重蹈覆辙吧。 起初报错内容如下所示&#xff1a; 一开始关注点在下面…

每天一道算法题(一)——在数组中找到目标值的之和的两个整数下标

文章目录 1、问题2、示例2、解决 1、问题 给定一个整数数组 nums 和一个整数目标值 target&#xff0c;请你在该数组中找出 和为目标值 target 的那 两个 整数&#xff0c;并返回它们的数组下标。你可以假设每种输入只会对应一个答案。但是&#xff0c;数组中同一个元素在答案里…

ubuntu提高 github下载速度

Github一般用于Git的远程仓库&#xff0c;由于服务器位于国外&#xff0c;国内访问速度比较慢&#xff0c;为了提高访问速度&#xff0c;决定绕过DNS域名解析。 获取Github的IP地址 按下ctrl&#xff0b;alt&#xff0b;T打开命令终端&#xff0c;输入&#xff1a; nslookup gi…

玩具、儿童用品、儿童服装上亚马逊TEMU平台CPC认证办理

CPC认证是Childrens Product Certificate的简称&#xff0c;即儿童产品证书。它是美国强制性法规CPSIA要求的一部分&#xff0c;该法规主要针对12岁及以下儿童使用的产品&#xff0c;如玩具、儿童用品、儿童服装等。 一、儿童小汽车CPC测试项目可能会因产品标准和法规的不同而…

android初集成flutter,遇到的问题

环境 studio版本&#xff1a;2022.1.1 flutter版本&#xff1a;2.8.0 电脑&#xff1a;mac flutter项目总是报错&#xff0c;编译不过 以 Resources Root 加载 记得设置dart&#xff1a;主工程和flutter项目都需要设置&#xff0c;否则不出现手机链接 下面这个样子就是好了&…

窗口管理工具 Mosaic mac中文版功能特点

MosAIc mac是一种窗口管理工具&#xff0c;可帮助您在计算机屏幕上有效地组织和管理多个应用程序窗口。它提供了一种直观的方式来调整和排列窗口&#xff0c;以最大化工作效率。 MosAIc mac窗口管理软件功能和特点 窗口布局&#xff1a;MosAIc允许您选择不同的窗口布局&#x…

抠某区域地图方法

1.打开阿里云数据可视化平台DataV.GeoAtlas地理小工具系列 2. 选择要抠出来的区域&#xff0c;右侧选择要下载的json文件&#xff0c;如红框所示 3. 打开下载的文件&#xff0c;内容全部复制。 4. 打开百度地图示例Examples - Apache ECharts 5. 如下图所示&#xff0c;将下…

数字化转型时代,商业智能BI到底是什么?

据国际数据公司&#xff08;IDC&#xff09;预测&#xff0c;2025年时中国产生的数据量预计将达48.6ZB&#xff0c;在全球中的比例为27.8%。商业智能BI这一专为企业提供服务的数据类解决方案&#xff0c;仅2021年上半年在中国商业智能BI市场规模就达到了3.2亿美元&#xff0c;商…

(二)什么是Vite——Vite 和 Webpack 区别(冷启动)

vite分享ppt&#xff0c;感兴趣的可以下载&#xff1a; ​​​​​​​Vite分享、原理介绍ppt 什么是vite系列目录&#xff1a; &#xff08;一&#xff09;什么是Vite——vite介绍与使用-CSDN博客 &#xff08;二&#xff09;什么是Vite——Vite 和 Webpack 区别&#xff0…

电源线虚接,导致信号线发烫

音频板的信号是经过隔直电容接到音频板的。

Nginx在实际使用中的常用基本配置

一、什么是Nginx Nginx 是开源的轻量级 Web 服务器、反向代理服务器&#xff0c;以及负载均衡器和 HTTP 缓存器。其特点是高并发&#xff0c;高性能和低内存。 Nginx 专为性能优化而开发&#xff0c;性能是其最重要的考量&#xff0c;实现上非常注重效率&#xff0c;能经受高负…

Linux应用开发基础知识——电阻屏和电容屏(八)

触摸屏分为电阻屏、 电容屏。电阻屏结构简单&#xff0c; 在以前很流行&#xff1b;电容屏支持 多点触摸&#xff0c;现在的手机基本都是使用电容屏。 注意&#xff1a;LCD、触摸屏不是一回事&#xff0c;LCD 是输出设备&#xff0c;触摸屏是输入设备。制作触摸 屏时特意把它的…

数据结构八种内部排序算法c++实现

文章目录 直接插入排序希尔排序冒泡排序快速排序选择排序堆排序归并排序桶排序 直接插入排序 vector<int> insertSort(vector<int> num) {int i, j, temp;for (i 1; i < num.size(); i){temp num[i];for (j i - 1; j > 0 && temp<num[j]; j-…

mysqldump常用操作示例/命令

以下是一些常用的mysqldump操作示例&#xff0c;以备份和还原MySQL数据库为例&#xff1a; 1. 备份单个数据库&#xff1a; mysqldump -u your_username -p your_password your_database > backup.sql将 your_username 替换为你的MySQL用户名&#xff0c;your_password 替…

反序列化漏洞(1), 原理, 实验, 魔术方法

反序列化漏洞(1), 原理, 实验, 魔术方法 一, 介绍 反序列化漏洞是一种存在于反序列化过程中的漏洞&#xff0c;它允许攻击者通过控制反序列化的数据来操纵序列化对象&#xff0c;并将有害数据传递给应用程序代码。 这种漏洞可能造成代码执行、获取系统权限等一系列不可控的后…