WPF/C#:异常处理

什么是异常?

在C#中,异常是在程序执行过程中发生的特殊情况,例如尝试除以零、访问不存在的文件、网络连接中断等。这些情况会中断程序的正常流程。

当C#程序中发生这种特殊情况时,会创建一个异常对象并将其抛出。这个异常对象包含了关于异常的详细信息,如异常类型和异常发生时的程序状态。

异常处理是一个重要的编程概念,它允许程序员在异常发生时采取适当的行动,而不是让程序崩溃。在C#中,我们使用try,catch和finally关键字来处理异常。

比如,下面的代码用0除一个数时,会出现一个异常:

internal class Program
{static void Main(string[] args){int x = 10, y = 0;x /= y;}
}

image-20240612074703674

try语句

try语句用来指明为避免出现异常而被保护的代码段,并在发生异常时提供代码处理异常。try语句由3个部分组成,如下图所示:

image-20240612081134390

处理异常

上面除以0会导致一个异常的程序,可以进行如下改写,进行异常处理:

internal class Program
{static void Main(string[] args){int x = 10;try{int y = 0;x /= y;}catch{Console.WriteLine("Handling all exceptions");}}
}

异常被捕获:

image-20240612081753905

异常类

在C#中,所有的异常都是派生自System.Exception类的。System.Exception类是所有异常的基类,它提供了一些基本的功能,如返回错误消息和记录异常发生的堆栈跟踪。
C#提供了一些内置的异常类,用于表示常见的异常情况。例如:

  • System.NullReferenceException:当你试图访问一个null对象的成员时,会抛出这个异常。
  • System.DivideByZeroException:当你试图除以零时,会抛出这个异常。
  • System.IndexOutOfRangeException:当你试图访问数组或集合的无效索引时,会抛出这个异常。
  • System.IO.FileNotFoundException:当试图打开的文件不存在时,会抛出这个异常。

当一个异常发生时,CLR会创建该类型的异常对象,并寻找适当的catch子句处理它。

所有异常类从根本上派生自System.Exception类,异常继承层次的一个部分如下所示:

image-20240612083327072

catch子句

catch子句处理异常。它有3种形式,允许不同级别的处理,如下图所示:

image-20240612085205550

  • 一般catch子句:这种形式的catch子句可以捕获任何类型的异常。它不指定异常类型,所以它会捕获try块中抛出的所有异常。
  • 特定catch子句:这种形式的catch子句只捕获指定类型的异常。如果try块中抛出的异常类型与catch子句中指定的类型匹配,那么就会执行这个catch子句。
  • 带对象的特定catch子句:这种形式的catch子句不仅指定了异常类型,还定义了一个异常对象。这个异常对象可以用来访问关于异常的更多信息,如错误消息和堆栈跟踪。

将开头的例子,修改为使用带对象的特定catch子句,如下所示:

 internal class Program{static void Main(string[] args){int x = 10;try{int y = 0;x /= y;}catch(DivideByZeroException e){Console.WriteLine($"Message:{e.Message}");Console.WriteLine($"Source: {e.Source}");Console.WriteLine($"Stack: {e.StackTrace}");}         }}

输出结果如下所示:

image-20240612090547534

抛出异常

可以使用throw语句使代码显式地引发一个异常。throw语句的语法如下:

throw ExceptionObject;

好了,以上就是C#中关于异常处理的基础知识,现在我们结合WPF中的例子说明在WPF中如何进行异常处理的。

WPF中的异常处理

现在来看看ExceptionHandlingSecondaryUIThread这个例子,项目结构如下图所示:

image-20240612093133247

先来看一下这个项目的运行效果:

这个例子介绍了WPF中如何处理在辅助UI线程中发生的异常。

现在来看看是如何处理的。

StartSecondaryUIThreadButton按钮点击事件处理程序:

  private void startSecondaryUIThreadButton_Click(object sender, RoutedEventArgs e){// Creates and starts a secondary thread in a single threaded apartment (STA)var thread = new Thread(MethodRunningOnSecondaryUIThread);thread.SetApartmentState(ApartmentState.STA);thread.IsBackground = true;thread.Start();}

这段代码的主要目的是创建并启动一个新的辅助UI线程。

  thread.SetApartmentState(ApartmentState.STA);

这行代码设置了线程的公寓状态为STA(Single-Threaded Apartment)。在WPF中,所有的UI线程都必须是STA线程,因为UI元素不是线程安全的。

Single-Threaded Apartment(STA)介绍

在WPF(Windows Presentation Foundation)中,Single-Threaded Apartment(STA)是指一个线程模型,其中每个线程都维护自己的消息队列,并且所有的UI操作都在这个线程上进行。
在STA模型中,每个线程都有自己的内存空间,这意味着线程之间的数据不会共享,从而避免了多线程编程中的许多并发问题。这对于UI编程来说非常重要,因为UI元素通常不是线程安全的,所以所有的UI操作都必须在同一个线程上进行。
在WPF中,主UI线程默认就是一个STA线程。此外,你也可以创建其他的STA线程,但是每个STA线程都只能操作它自己创建的UI元素。

MethodRunningOnSecondaryUIThread方法如下所示:

 // THIS METHOD RUNS ON A SECONDARY UI THREAD (THREAD WITH A DISPATCHER)private void MethodRunningOnSecondaryUIThread(){var secondaryUiThreadId = Thread.CurrentThread.ManagedThreadId;try{// On secondary thread, show a new Window before starting a new Dispatcher// ie turn secondary thread into a UI threadvar window = new SecondaryUIThreadWindow();window.Show();Dispatcher.Run();}catch (Exception ex){// Dispatch the exception back to the main ui thread and reraise itApplication.Current.Dispatcher.Invoke(DispatcherPriority.Send,(DispatcherOperationCallback) delegate{// THIS CODE RUNS BACK ON THE MAIN UI THREADstring msg = $"Exception forwarded from secondary UI thread {secondaryUiThreadId}.";throw new Exception(msg, ex);}, null);// NOTE - Application execution will only continue from this point//        onwards if the exception was handled on the main UI thread//        by Application.DispatcherUnhandledException}}

在try语句块中创建了SecondaryUIThreadWindow。

SecondaryUIThreadWindow上的按钮的点击事件处理程序如下所示:

 private void raiseExceptionOnSecondaryUIThreadButton_Click(object sender, RoutedEventArgs e){// Raise an exception on the secondary UI threadstring msg = $"Exception raised on secondary UI thread {Dispatcher.Thread.ManagedThreadId}.";throw new Exception(msg);}

抛出了一个异常。

这个异常被MethodRunningOnSecondaryUIThread方法中的catch子句段捕获:

image-20240612095805302

 Application.Current.Dispatcher.Invoke(DispatcherPriority.Send,(DispatcherOperationCallback) delegate{// THIS CODE RUNS BACK ON THE MAIN UI THREADstring msg = $"Exception forwarded from secondary UI thread {secondaryUiThreadId}.";throw new Exception(msg, ex);}, null);

这段代码的主要目的是在辅助UI线程上捕获异常,并将异常转发到主UI线程上进行处理。

在app.xaml中

  DispatcherUnhandledException="App_DispatcherUnhandledException"

这行代码是在WPF应用程序中设置全局未处理异常的处理器。

当应用程序的主调度器捕获到未处理的异常时,App_DispatcherUnhandledException方法会被调用来处理这个异常。
这是一种处理全局未处理异常的方式,可以防止应用程序因为未处理的异常而崩溃。在App_DispatcherUnhandledException方法中,你可以记录异常信息,显示错误消息,或者决定是否让应用程序继续运行。

   private void App_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e){// Display exception messagevar sb = new StringBuilder();sb.AppendFormat("{0}\n", e.Exception.InnerException.Message);sb.AppendFormat("{0}\n", e.Exception.Message);sb.AppendFormat("Exception handled on main UI thread {0}.", e.Dispatcher.Thread.ManagedThreadId);MessageBox.Show(sb.ToString());// Keep application running in the face of this exceptione.Handled = true;}

这样就完成了在WPF中的辅助UI线程的异常处理。

还有一个例子是ExceptionHandlingSecondaryWorkerThread说明在WPF中如何处理在辅助工作线程(Secondary Worker Thread)中发生的异常,与这个例子类似。

参考

1、《C#图解教程》

2、[WPF-Samples/Application Management/ExceptionHandlingSecondaryUIThread at main · microsoft/WPF-Samples (github.com)](https://github.com/microsoft/WPF-Samples/tree/main/Application Management/ExceptionHandlingSecondaryUIThread)

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

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

相关文章

【纯血鸿蒙】——响应式布局如何实现?

前面介绍了自适应布局,但是将窗口尺寸变化较大时,仅仅依靠自适应布局可能出现图片异常放大或页面内容稀疏、留白过多等问题。此时就需要借助响应式布局能力调整页面结构。 响应式布局 响应式布局是指页面内的元素可以根据特定的特征(如窗口…

js实现一个数据结构——栈

栈的概念就不再赘述,无可厚非的先进后出,而JS又是高级语言,数组中的方法十分丰富,已经自带了push pop方法进行入栈出栈的操作。 1.基本实现 class Stack {constructor() {this.items [];}// 入栈push(item) {this.items.push(i…

Python学习笔记7:入门知识(七)

前言 之前说过我更换了新的学习路线,现在是根据官方文档和书籍Python crash course来进行学习的,在目前的学习中,对于之前的知识有一些遗漏,这里进行补充。 学习资料有两个,书籍中文版PDF,关注我私信发送…

SaaS产品运营 | 千万不能踏入的PLG模式的六大误区

随着科技的迅速发展和市场竞争的日益激烈,越来越多的公司开始尝试采用PLG(Product Led Growth,即产品驱动增长)模式来推动其业务的发展。然而,尽管PLG模式在促进增长方面具有显著优势,但在实践中也容易出现…

Centos: ifconfig command not found且ip addr查不到服务器IP

前段时间部门新派发了服务器,让我过去使用U盘装机,装完后使用ifconfig查不到服务器IP地址,ip addr也是查不到 ifconfig:command not found (这两个图片先用虚拟机的替代一下) 在网上找资料(CSDN,博客园,知乎…

Mysql学习笔记-进阶篇

一、存储引擎 1、MYSQL体系结构 连接层、服务层、引擎层、存储层; 2、存储引擎简介 存储引擎就是存储数据、建立索引、更新/查询数据等技术的实现方式。存储引擎是基于表的,而不是库的,所以存储引擎也可被称为表类型。 1)在创…

linux 安装 Nginx 并部署 vue 项目

1、安装 yum install nginx2、使用 nginx 命令 查看nginx状态 systemctl status nginx 启动服务 systemctl start nginx停止服务 systemctl stop nginx重启服务 systemctl restart nginx修改配置后重载 systemctl reload nginx3、nginx 常用目录 路径说明/etc/nginx/保…

tkinter文本对齐方式

tkinter文本对齐方式 文本对齐方式效果代码 文本对齐方式 左对齐(left):默认对齐方式,文本从左边界开始。右对齐(right):文本从右边界开始。居中对齐(center)&#xff1…

uniapp视频组件层级太高,解决方法使用subNvue原生子体窗口

目录 前言 先看一下uniapp官网的原话: subNvue的一些参数介绍 subNvues使用方法: 绑定id 显示 subNvue 弹出层 subNvue.show() 参数信息 subNvue.hide() 参数信息 在使用subNvue 原生子体窗口 遇到的一些问题 前言 nvue 兼容性 以及使用方式 控…

UE5基础1-下载安装

目录 一.下载 二.安装 三.安装引擎 四.其他 简介: UE5(Unreal Engine 5)是一款功能极其强大的游戏引擎。 它具有以下显著特点: 先进的图形技术:能够呈现出令人惊叹的逼真视觉效果,包括高逼真的光影、材…

185.二叉树:二叉搜索树的最近公共祖先(力扣)

代码解决 /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode(int x) : val(x), left(NULL), right(NULL) {}* };*/class Solution { public:// 函数用于寻找二叉搜索树中节点 p 和 q 的最低…

【python】OpenCV GUI——Trackbar(14.2)

学习来自 OpenCV基础(12)OpenCV GUI中的鼠标和滑动条 文章目录 GUI 滑条介绍cv2.createTrackbar 介绍牛刀小试 GUI 滑条介绍 GUI滑动条是一种直观且快速的调节控件,主要用于改变一个数值或相对值。以下是关于GUI滑动条的详细介绍&#xff1a…

如何利用智能家居打造一个“会呼吸的家”?一体化电动窗帘

如何利用智能家居打造一个“会呼吸的家”?一体化电动窗帘 史新华 隐藏式一体化智能电动窗帘与市面上其他窗帘不同的是,电机内置于轨道之中,一体化,美观、安静、滑动顺畅。 每次都会自动打开和关闭,相当漂亮。 众多家庭…

2002-2023年款别克君威 君威GS维修手册和电路图资料更新

经过整理,2002-2023年款别克君威 君威GS全系列已经更新至汽修帮手资料库内,覆盖市面上99%车型,包括维修手册、电路图、新车特征、车身钣金维修数据、全车拆装、扭力、发动机大修、发动机正时、保养、电路图、针脚定义、模块传感器、保险丝盒图…

双Token方案实现Token自动续期(基于springboot+vue前后端分离项目)

文章目录 前言一、双Token方案介绍1. 令牌类型与功能2.双Token方案的优点3.实现流程 二、具体实现1.后端实现1.1 jwt工具类1.2 响应工具类1.3 实体类1.4 过滤器1.5 controller1.6 启动类 2、前端实现2.1 登录页面2.2 index页面2.3 请求拦截器和响应拦截器 效果展示 前言 更多j…

短剧APP小程序开发之小程序内存管理挑战:短剧缓存与释放策略探讨(第二篇)

在上一篇帖子中,我们探讨了小程序内存管理的限制以及缓存策略的设计。本篇将进一步探讨释放策略的具体实现以及优化方案,以支持大量短剧内容的加载和播放。 释放策略的具体实现 监听内存警告:小程序提供了监听内存警告的API,开发…

【译】SQLAlchemy文档:SQLAlchemy 统一教程

SQLAlchemy Unified Tutorial SQLAlchemy 是 Python SQL工具包和ORM,它为应用程序开发人员提供了 SQL 的全部功能和灵活性。它提供了一整套企业级持久性模式,专为高效和高性能的数据库访问而设计。 SQLAlchemy呈现为两层API:Core和ORM&…

【记录】ChatGLM3-6B大模型部署、微调(一):部署

ChatGLM3介绍 源码连接: ChatGLM3 是智谱AI和清华大学 KEG 实验室联合发布的对话预训练模型。ChatGLM3-6B 是 ChatGLM3 系列中的开源模型,在保留了前两代模型对话流畅、部署门槛低等众多优秀特性的基础上,ChatGLM3-6B 引入了如下特性&#xf…

如何高效管理和监控 Elasticsearch 别名及索引?

0、引言 在 Elasticsearch 项目中,管理和监控索引是开发者的一项重要任务。 尤其是当我们需要在项目的管理部分展示索引和别名的统计信息时,了解如何有效地列出这些别名和索引显得尤为重要。 本篇博客将介绍几种在 Elasticsearch 中列出别名和索引的方法…