学习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.mfbz.cn/a/157529.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

vulnhub靶机Momentum2

下载地址&#xff1a;https://download.vulnhub.com/momentum/Momentum2.ova 主机发现 端口扫描 端口服务扫描 漏洞扫描 先去看看web 这里面没有什么&#xff0c;就顺手扫一下目录 发现一些可疑的目录 比较正常 再看一下有没有别的web 看到几个新的东西去看看 文件上传 啥都没…

8.jib-maven-plugin构建springboot项目镜像,docker部署配置

目录 1.构建、推送镜像 1.1 执行脚本 2.2 pom.xml配置 ​2.部署镜像服务 2.1 执行脚本 2.2 compose文件 3.docker stack常用命令 介绍&#xff1a;使用goole jib插件构建镜像&#xff0c;docker stack启动部署服务&#xff1b; 通过执行两个脚本既可以实现构建镜像、部…

实时音视频方案汇总

若有好的方案欢迎留言讨论&#xff0c;非常感谢&#xff0c;汇总了一些&#xff0c;从市面上了解的一些低时延的端到端的方案&#xff0c;仅供参照&#xff0c;若有问题&#xff0c;也欢迎留言更正&#xff01; 方案 方案描述 时延 备注 1大华同轴高清电缆200米电缆&#xf…

Mysql之多表查询下篇

Mysql之多表查询下篇 满外连接的实现UNION关键字UNIONUNION ALL操作符 7种SQL JOINS的实现语法格式小结自然连接USING连接表连接的约束条件 满外连接的实现 在上篇博客中&#xff0c;我们可以了解到在Mysql中是不支持FULL JOIN来实现 满外连接的&#xff0c;那么我们在Mysql采用…

“鸿蒙之父”确认鸿蒙 PC 来了;腾讯是囤积 AI 芯片最多的中国科技公司之一丨 RTE 开发者日报 Vol.87

开发者朋友们大家好&#xff1a; 这里是 「RTE 开发者日报」 &#xff0c;每天和大家一起看新闻、聊八卦。我们的社区编辑团队会整理分享 RTE &#xff08;Real Time Engagement&#xff09; 领域内「有话题的 新闻 」、「有态度的 观点 」、「有意思的 数据 」、「有思考的 文…

Cow Lineup S——离散化、单调队列、双指针

题目描述 思路 x、id不大于1亿&#xff0c;数据量太大&#xff0c;使用离散化将id离散化成一串从1开始连续的编号&#xff0c;使用map集合进行离散化使用双指针维护一段区间&#xff0c;这段区间满足每个编号都包含 如何使用map集合进行离散化&#xff1f; 维护一个变量nums…

如何将中文翻译成荷兰语?

随着中国的崛起&#xff0c;荷兰与中国的交流日益频繁。越来越多的企业和个人需要荷兰语翻译服务。那么&#xff0c;如何将中文翻译成荷兰语&#xff0c;北京哪家翻译公司比较专业&#xff1f; 专业人士指出&#xff0c;要提供优质的荷兰语翻译服务&#xff0c;不仅需要扎实的荷…

如何为初创企业选择合适的 ERP 系统?

**ERP系统**是制造、分销、供应链、金融、会计、风险管理等多个行业必不可少的企业技术解决方案。不论垂直行业、企业规模或目标受众如何&#xff0c;将ERP作为企业管理战略的核心部分都非常重要。 对于渴望发展的小型企业和初创企业来说&#xff0c;更是如此。大型企业需要对…

Maven依赖管理项目构建工具(保姆级教学)

一、Maven介绍 官网地址&#xff1a;Maven – Introduction Maven 是一款为 Java 项目管理构建、依赖管理的工具&#xff08;软件&#xff09;&#xff0c;使用 Maven 可以自动化构建、测试、打包和发布项目&#xff0c;大大提高了开发效率和质量。 Maven就是一个软件&#…

mysql索引学习案例

简单的学习一下mysql普通索引 这是一个小的案例 一、创建表SQL CREATE TABLE group_order (id int(11) NOT NULL AUTO_INCREMENT,group_seq varchar(64) COLLATE utf8mb4_bin NOT NULL COMMENT 拼单号,group_status int(8) NOT NULL COMMENT 100 待提货, 200 已提货, 300 已…

2024年山东省职业院校技能大赛中职组 “网络安全”赛项竞赛试题-B卷

2024年山东省职业院校技能大赛中职组 “网络安全”赛项竞赛试题-B卷 2024年山东省职业院校技能大赛中职组 “网络安全”赛项竞赛试题-B卷A模块基础设施设置/安全加固&#xff08;200分&#xff09;A-1&#xff1a;登录安全加固&#xff08;Windows, Linux&#xff09;A-2&#…

vite+vue3+ts中watch和watchEffct的使用

vitevue3ts中watch和watchEffct的使用 本文目录 vitevue3ts中watch和watchEffct的使用watchrefreactivepropsimmediate组合监听 watchEffect单值多值侦听副作用停止监听 watch vue官方文档&#xff1a;https://cn.vuejs.org/api/reactivity-core.html#watch 可以监听基础类型&…

cookie机制 + java 案例

目录 为什么会有cookie?? cookie从哪里来的&#xff1f;&#xff1f; cookie到哪里去&#xff1f;&#xff1f; cookie有啥用&#xff1f;&#xff1f; session HttpServletRequest类中的相关方法 简单的实现cookie登录功能 实现登录页面 实现servlet逻辑 实现生成主…

牛客机考题编程题输入输出

有时空可以练练这里的题目&#xff1a; https://ac.nowcoder.com/acm/contest/5652 做个总结&#xff0c;其实就两种输入类型&#xff1a; 一种是下面这种&#xff0c;需要对输入的每行进行运算 这种就是循环读取每行的数做一个运算&#xff1a; import sys while True:line …

【Nuxt】Nuxt3 动态导入图片 src

nuxt3 不再支持 require 动态导入资源&#xff0c;因此需要我们将图片放到 public 目录下&#xff0c;这样我们就可以动态导入了 比如下面 &#x1f447;&#xff1a; 感谢 Nuxt3遇见的坑&#xff08;四&#xff09;&#xff1a;图片动态渲染之后打包路径问题以及打包css样式…

代码混淆的原理是什么?常见代码混淆方法介绍

​ 代码混淆的原理是什么&#xff1f;常见代码混淆方法介绍 本文主要想你介绍代码混淆的原理&#xff0c;常见代码混淆方法&#xff0c;欢迎查阅~ 移动应用代码安全非常重要&#xff0c;代码逆向会导致代码逻辑被获取&#xff0c;进一步导致控制流被hook&#xff0c;安全防线被…

SystemVerilog学习 (11)——覆盖率

目录 一、概述 二、覆盖率的种类 1、概述 2、分类 三、代码覆盖率 四、功能覆盖率 五、从功能描述到覆盖率 一、概述 “验证如果没有量化&#xff0c;那么就意味着没有尽头。” 伴随着复杂SoC系统的验证难度系数成倍增加&#xff0c;无论是定向测试还是随机测试&#xff…

reids面试题

1 redis是单线程吗&#xff1f; Redis是单线程 主要是指Redis的网络10和键值对读写是由一个线程来完成的&#xff0c;Redis在处理客户端的请求时包括获取(socket 读)、解析、执行、内容返回(socket 写) 等都由一个顺序串行的主线程处理&#xff0c; 但Redis的其他功能&#xff…

结合 Django 和 Vue.js 打造现代 Web 应用

概要 在 Web 开发的世界里&#xff0c;Django 和 Vue.js 分别是后端和前端两个非常流行的框架。Django 以其强大的后端能力、快速开发以及安全性而著称&#xff0c;而 Vue.js 因其简洁、灵活和易于上手在前端开发领域广受欢迎。 本篇文章将详细介绍如何将 Django 与 Vue.js 结…

Jetson简介、编程开发与环境搭建

Jetson简介、编程开发与环境搭建 简介常用指令Jetpack环境搭建 简介 Jetson是由NVIDIA推出的一系列嵌入式系统&#xff0c;旨在用于机器学习和人工智能应用的开发。Jetson平台通常使用NVIDIA的GPU加速技术&#xff0c;以提供高性能的计算能力。NVIDIA推出了多个Jetson系列的产…