WPF/C#:异常处理

news2025/1/6 18:52:10

什么是异常?

在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 thread
         var window = new SecondaryUIThreadWindow();
         window.Show();
         Dispatcher.Run();
     }
     catch (Exception ex)
     {
         // Dispatch the exception back to the main ui thread and reraise it
         Application.Current.Dispatcher.Invoke(
             DispatcherPriority.Send,
             (DispatcherOperationCallback) delegate
             {
                 // THIS CODE RUNS BACK ON THE MAIN UI THREAD
                 string 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 thread
     string 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 THREAD
         string 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 message
       var 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 exception
       e.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.coloradmin.cn/o/1829384.html

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

相关文章

Floyd-Warshall

应用场景 要求出每两点之间的最短路。或判断两点之间的连通性&#xff08;两点之间是否有路径&#xff09;。 板子 代码&#xff08;必背!!!&#xff09; for(int k 1; k < n; k)for(int i 1; i < n; i)for(int j 1; j < n; j)d[i][j] min(d[i][j], d[i][k] …

堆的基本概念

堆 堆是一个完全二叉树 完全二叉树的要求&#xff0c;除了最后一层&#xff0c;其他层的节点个数都是满的&#xff0c;最后一层的节点都靠左排列 堆中每一个节点的值都必须大于等于(或小于等于)其子树中每个节点的值 堆中每个节点的值都大于等于(或者小于等于)其左右子节点的值…

C#(C Sharp)学习笔记_封装【十八】

什么是封装&#xff1f; 封装是面向对象思维的三大特性之一。封装是将数据和对数据进行操作的函数绑定到一起的机制。它隐藏了对象的内部状态和实现细节&#xff0c;只对外提供必要的接口&#xff0c;从而确保对象内部状态的完整性和安全性。封装的主要目的是增强安全性和简化…

登录MySQL方式

登录MySQL方式 方式一&#xff1a;通过MySQL自带的客户端 MySQL 客户端输入命令即可 方式二&#xff1a;通过window自带的客户端 从命令端&#xff08;cmd&#xff09;进入 mysql -h localhost -P 3306 -u root -p Enter password:密码登录方式&#xff1a; mysql -h 主…

【LeetCode最详尽解答】11-盛最多水的容器 Container-With-Most-Water

欢迎收藏Star我的Machine Learning Blog:https://github.com/purepisces/Wenqing-Machine_Learning_Blog。如果收藏star, 有问题可以随时与我交流, 谢谢大家&#xff01; 链接&#xff1a; 11-盛最多水的容器 直觉 这个问题可以通过可视化图表来理解和解决。 通过图形化这个…

基于51单片机万年历设计—显示温度农历

基于51单片机万年历设计 &#xff08;仿真&#xff0b;程序&#xff0b;原理图&#xff0b;设计报告&#xff09; 功能介绍 具体功能&#xff1a; 本系统采用单片机DS1302时钟芯片LCD1602液晶18b20温度传感器按键蜂鸣器设计而成。 1.可以显示年月日、时分秒、星期、温度值。…

mySql的事务(操作一下)

目录 1. 简介2. 事务操作3. 四大特性4. 并发事务问题5. 脏读6. 不可重复读7. 幻读事务隔离级别参考链接 1. 简介 事务是一组操作的集合&#xff0c;它是一个不可分割的工作单位&#xff0c;事务会把所有的操作作为一个整体一起向系统提交或撤销操作请求&#xff0c;即这些操作…

机器学习(V)--无监督学习(二)主成分分析

当数据的维度很高时&#xff0c;很多机器学习问题变得相当困难&#xff0c;这种现象被称为维度灾难&#xff08;curse of dimensionality&#xff09;。 在很多实际的问题中&#xff0c;虽然训练数据是高维的&#xff0c;但是与学习任务相关也许仅仅是其中的一个低维子空间&am…

【Java】Object、Objects、包装类、StringBuilder、StringJoiner

目录 1.API2.Object类3.Objects类4.包装类4.1包装类概述4.2包装类的其他常见操作 5.StringBuilder 可变字符串5.1概述5.2StringBuilder案例 6.StringJoiner 1.API API&#xff1a;应用程序编程接口&#xff0c;全称application programing interface&#xff0c;即Java已经写好…

分享一个 .NET Core 使用选项方式读取配置内容的详细例子

前言 在 .NET Core 中&#xff0c;可以使用选项模式&#xff08;Options Pattern&#xff09;来读取和管理应用程序的配置内容。 选项模式通过创建一个 POCO&#xff08;Plain Old CLR Object&#xff09;来表示配置选项&#xff0c;并将其注册到依赖注入容器中&#xff0c;方…

Spring AI探索

Spring AI概述 该Spring AI项目旨在简化包含人工智能功能的应用程序的开发&#xff0c;避免不必要的复杂性。 该项目从著名的 Python 项目&#xff08;例如 LangChain 和 LlamaIndex&#xff09;中汲取灵感&#xff0c;但 Spring AI 并非这些项目的直接移植。该项目的成立基于…

Linux内核编程(五)ioctl驱动编写

本文目录 一、系统层和内核层接口1. ioctl系统层接口2. ioctl内核层接口 二、标准 unlocked_ioctl 接口的命令合成三、代码编程 ioctl 主要用于实现对硬件设备控制类操作&#xff0c;实现 write 和 read 不太好实现的功能。 ioctl 是一个强大的工具&#xff0c;可以用于实现复杂…

​单级高频谐振小放

目录 高频交流等效电路 质量指标 增益 通频带 选择性 高频交流等效电路 质量指标 增益 YL撇是怎么来的。 通频带 选择性

Spark常见的可以优化的点

Shuffle 复用 # 1.以下操作会复用的shuffle结果&#xff0c;只会读一遍数据源 val rdd1 sc.textFile("hdfs://zjyprc-hadoop/tmp/hive-site.xml").flatMap(_.split(" ")).map(x > (x,1)).reduceByKey(_ _).filter(_._2 > 1) rdd1.count() rdd1.fil…

基于dagger平台实现资源位的接口自动化

文章目录 什么是dagger平台&#xff1f;什么是资源位&#xff1f;什么是接口自动化&#xff1f;如何实现接口自动化&#xff1f;内部调用关系基本概念互相引用关系 目录结构具体实现任务&#xff1a;Task用例&#xff1a;Case场景&#xff1a;Scene接口&#xff1a;Api 监控与数…

基于Itô扩散过程的交易策略偏微分方程matlab求解与仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.本算法原理 5.完整程序 1.程序功能描述 基于It扩散过程的交易策略偏微分方程,提出了一种确定It扩散过程。通过根据的第一次通过时间来确定问题在这个过程中&#xff0c;我们推导出交易长度的分布函数和密…

如何通过Outlook大附件插件,加强外发附件的安全性和管控力度?

因邮件的便捷性和普遍性&#xff0c;企业间业务往来通常会采取邮箱业务&#xff0c;沟通使用成本也比较低&#xff0c;但容易出现附件太大无法上传的问题。Outlook大附件插件是为解决邮件系统中附件大小限制问题而开发的一系列工具。 使用邮件发送附件时&#xff0c;可能会遇到…

R调用Taxonkit展示系统发育信息

Introduction TaxonKit是一个用于处理生物分类学数据的命令行工具。 它的主要功能是处理NCBI的生物分类学数据&#xff0c;包括对分类单元&#xff08;如物种、属、科等&#xff09;的查找、分类单元的上下位关系查询、分类单元名称的标准化等。 为了方便R社区用户&#xff0…

QuickLook最强大的C#开源文件预览神器

功能特点&#xff1a; 快速预览&#xff1a;用户只需选中文件并按下空格键&#xff0c;即可立即查看文件内容&#xff0c;无需打开特定应用程序或软件。 多格式支持&#xff1a;QuickLook支持预览几乎所有常见的文件类型&#xff0c;包括但不限于&#xff1a; 图像&#xff1…

【计算机网络】已解决:“‘ping‘ 不是内部或外部命令,也不是可运行的程序或批处理文件”报错

文章目录 一、问题分析背景二、可能出错的原因三、错误代码示例四、正确解决方法与示例五、注意事项 已解决“‘ping’ 不是内部或外部命令&#xff0c;也不是可运行的程序或批处理文件”报错 一、问题分析背景 在Windows操作系统中&#xff0c;ping 命令是一个常用的网络诊断…