jjzjj

c# - 多种形式的异常处理

coder 2024-06-02 原文

我在调试时和在运行已编译的 .exe 时看到异常被捕获或未被捕获的不同行为。我有两种形式(Form1 和 Form2)。 Form1 上有一个按钮,它在 Form2 上实例化并调用 ShowDialog。 Form2 上有一个按钮,它有意产生被零除的错误。当我调试时,命中了 Form1 中的 catch block 。当我运行已编译的 .exe 时,它​​没有命中,而是出现一个消息框,指出“您的应用程序中发生了未处理的异常。如果您单击继续,应用程序将忽略此错误并尝试继续。如果您单击退出,应用程序将立即关闭...试图除以零”。我的问题是为什么在调试时和运行 .exe 时会出现不同的行为?如果这是预期的行为,那么是否认为有必要在每个事件处理程序中放置 try/catch block ?这似乎有点疯狂,不是吗?

这是 Form1 的代码。

public partial class Form1 : Form
{
    public Form1()
    {
            InitializeComponent();

    }

    private void button1_Click(object sender, EventArgs e)
    {
        try
        {
            Form2 f2 = new Form2();
            f2.ShowDialog();
        }
        catch(Exception eX)
        {
            MessageBox.Show( eX.ToString()); //This line hit when debugging only
        }
    }
}

这是 Form2 的代码:

public partial class Form2 : Form
{
    public Form2()
    {
            InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
            int x = 0;
            int y = 7 / x;

    }
}

最佳答案

是的,这是设计使然,并且与 Windows 窗体的工作方式密切相关。在 Winforms 应用程序中,代码运行以响应 Windows 发布到事件窗口的消息。每个 native Windows 应用程序都包含一个消息循环来检测这些消息。 Winforms 管道确保您的事件处理程序之一运行响应; button1_Click 在您的示例代码中。

大多数 Winforms 控件都实现了自己的事件处理程序。例如,PictureBox 有一个 Paint 事件处理程序,可确保将其图像绘制到屏幕上。这一切都是自动完成的,您无需自己编写任何代码来完成这项工作。

但是当这段代码抛出异常时会出现问题,您无法捕获此类异常,因为没有涉及您自己的代码。换句话说,您没有地方可以注入(inject)自己的 try block 。您自己的程序代码的最后一部分是启动消息循环的代码。 Application.Run() 方法调用,通常在 Program.cs 中。或者,如果显示对话框,则调用 Form.ShowDialog()。这些方法中的任何一个都会启动消息循环。在 Application.Run() 调用周围放置一个 try block 没有用,应用程序将在捕获异常后终止。

为了解决这个问题,Winforms 消息循环代码在调度事件的代码周围包含一个 try block 。它的catch子句显示你提到的对话框,它是由ThreadExceptionDialog类实现的。

进入您的问题的要点:这个 catch 子句确实妨碍了您在调试时对代码问题进行故障排除。只有在没有处理异常的 catch block 时,调试器才会在出现异常时停止。但是当您的代码抛出异常时,您会想在调试时了解它。前面提到的消息循环中的代码知道是否附加了调试器。如果是,它会在没有 try/catch block 的情况下分派(dispatch)事件。现在,当您的代码抛出异常时,没有 catch 子句来处理它,调试器将停止程序,让您有机会找出问题所在。

也许您现在明白了为什么您的程序会这样运行。调试时,消息循环中的 catch 子句被禁用,从而使 Form1 代码中的 catch 子句有机会捕获异常。如果您不这样做,消息循环 catch 子句会处理异常(通过显示对话框)并防止异常展开到 Form1 代码。

您可以通过调用 Application.SetUnhandledExceptionMode() 方法并传递 UnhandledExceptionMode.ThrowException 来阻止使用消息循环 catch 子句。在 Main() 方法中执行此操作,在 Application.Run() 调用之前。现在您的程序在任何一种方式下的行为都相同。

这通常不是一个坏主意,让用户在异常对话框中选择“继续”是一个值得怀疑的功能。在这种情况下,请务必为 AppDomain.UnhandledException 事件实现事件处理程序,以便至少为用户提供一些诊断信息。

关于c# - 多种形式的异常处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1775887/

有关c# - 多种形式的异常处理的更多相关文章

  1. ruby - 如何指定 Rack 处理程序 - 2

    Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack

  2. ruby-on-rails - Rails - 乐观锁定总是触发 StaleObjectError 异常 - 2

    我正在学习Rails,并阅读了关于乐观锁的内容。我已将类型为integer的lock_version列添加到我的articles表中。但现在每当我第一次尝试更新记录时,我都会收到StaleObjectError异常。这是我的迁移:classAddLockVersionToArticle当我尝试通过Rails控制台更新文章时:article=Article.first=>#我这样做:article.title="newtitle"article.save我明白了:(0.3ms)begintransaction(0.3ms)UPDATE"articles"SET"title"='dwdwd

  3. ruby - #之间? Cooper 的 *Beginning Ruby* 中的错误或异常 - 2

    在Cooper的书BeginningRuby中,第166页有一个我无法重现的示例。classSongincludeComparableattr_accessor:lengthdef(other)@lengthother.lengthenddefinitialize(song_name,length)@song_name=song_name@length=lengthendenda=Song.new('Rockaroundtheclock',143)b=Song.new('BohemianRhapsody',544)c=Song.new('MinuteWaltz',60)a.betwee

  4. c# - 如何在 ruby​​ 中调用 C# dll? - 2

    如何在ruby​​中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL

  5. ruby - 在 Ruby 中重新分配常量时抛出异常? - 2

    我早就知道Ruby中的“常量”(即大写的变量名)不是真正常量。与其他编程语言一样,对对象的引用是唯一存储在变量/常量中的东西。(侧边栏:Ruby确实具有“卡住”引用对象不被修改的功能,据我所知,许多其他语言都没有提供这种功能。)所以这是我的问题:当您将一个值重新分配给常量时,您会收到如下警告:>>FOO='bar'=>"bar">>FOO='baz'(irb):2:warning:alreadyinitializedconstantFOO=>"baz"有没有办法强制Ruby抛出异常而不是打印警告?很难弄清楚为什么有时会发生重新分配。 最佳答案

  6. C# 到 Ruby sha1 base64 编码 - 2

    我正在尝试在Ruby中复制Convert.ToBase64String()行为。这是我的C#代码:varsha1=newSHA1CryptoServiceProvider();varpasswordBytes=Encoding.UTF8.GetBytes("password");varpasswordHash=sha1.ComputeHash(passwordBytes);returnConvert.ToBase64String(passwordHash);//returns"W6ph5Mm5Pz8GgiULbPgzG37mj9g="当我在Ruby中尝试同样的事情时,我得到了相同sha

  7. ruby-on-rails - 使用回形针的嵌套形式 - 2

    我有一个名为posts的模型,它有很多附件。附件模型使用回形针。我制作了一个用于创建附件的独立模型,效果很好,这是此处说明的View(https://github.com/thoughtbot/paperclip):@attachment,:html=>{:multipart=>true}do|form|%>posts中的嵌套表单如下所示:prohibitedthispostfrombeingsaved:@attachment,:html=>{:multipart=>true}do|at_form|%>附件记录已创建,但它是空的。文件未上传。同时,帖子已成功创建...有什么想法吗?

  8. ruby - nanoc 和多种布局 - 2

    是否可以为特定(或所有)项目使用多个布局?例如,我有几个项目,我想对其应用两种不同的布局。一个是绿色的,一个是蓝色的(但是)。我想将它们编译到我的输出目录中的两个不同文件夹中(例如v1和v2)。我一直在玩弄规则和编译block,但我不知道这是怎么回事。因为,每个项目在编译过程中只编译一次,我不能告诉nanoc第一次用layout1编译,第二次用layout2编译。我试过这样的东西,但它导致输出文件损坏。compile'*'doifitem.binary?#don’tfilterbinaryitemselsefilter:erblayout'layout1'layout'layout2'

  9. 基于C#实现简易绘图工具【100010177】 - 2

    C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.

  10. SPI接收数据异常问题总结 - 2

    SPI接收数据左移一位问题目录SPI接收数据左移一位问题一、问题描述二、问题分析三、探究原理四、经验总结最近在工作在学习调试SPI的过程中遇到一个问题——接收数据整体向左移了一位(1bit)。SPI数据收发是数据交换,因此接收数据时从第二个字节开始才是有效数据,也就是数据整体向右移一个字节(1byte)。请教前辈之后也没有得到解决,通过在网上查阅前人经验终于解决问题,所以写一个避坑经验总结。实际背景:MCU与一款芯片使用spi通信,MCU作为主机,芯片作为从机。这款芯片采用的是它规定的六线SPI,多了两根线:RDY和INT,这样从机就可以主动请求主机给主机发送数据了。一、问题描述根据从机芯片手

随机推荐