Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/272.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 为什么异常抛出行为是;ShowDialog“;如果在连接Visual Studio调试器的情况下启动,会有什么不同?_C#_Winforms - Fatal编程技术网

C# 为什么异常抛出行为是;ShowDialog“;如果在连接Visual Studio调试器的情况下启动,会有什么不同?

C# 为什么异常抛出行为是;ShowDialog“;如果在连接Visual Studio调试器的情况下启动,会有什么不同?,c#,winforms,C#,Winforms,考虑一下:Form1以模式对话框的形式启动Form2,并调用“System.Windows.Forms.Form.ShowDialog”。Form2在GUI线程上引发异常 如果我从VisualStudio调试器运行此程序,我可以在Form1中的调用站点捕获此异常(我没有预料到!)。如果我没有在没有附加调试器的情况下启动程序,即使稍后附加调试器,我也无法从Form1捕获异常(这是我所期望的行为) 为什么在调试器下运行时可以捕获Form1中的异常?或者,更重要的是,为什么调试器的存在会改变“Show

考虑一下:Form1以模式对话框的形式启动Form2,并调用“System.Windows.Forms.Form.ShowDialog”。Form2在GUI线程上引发异常

如果我从VisualStudio调试器运行此程序,我可以在Form1中的调用站点捕获此异常(我没有预料到!)。如果我没有在没有附加调试器的情况下启动程序,即使稍后附加调试器,我也无法从Form1捕获异常(这是我所期望的行为)

为什么在调试器下运行时可以捕获Form1中的异常?或者,更重要的是,为什么调试器的存在会改变“ShowDialog”的异常抛出行为

以下代码足以说明该问题

using System;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
        }
    }

    public class Form1 : Form
    {
        public Form1()
        {
            this.MouseClick += this.OnMouseClick;
        }

        private void OnMouseClick(object sender, MouseEventArgs e)
        {
            try
            {
                var f2 = new Form2();
                f2.ShowDialog(this);
            }
            catch (System.Exception ex)
            {
                MessageBox.Show(this, ex.Message, "Exception Caught!",
                    MessageBoxButtons.OK, MessageBoxIcon.Information
                    );
            }
        }
    }

    public class Form2 : Form
    {
        public Form2()
        {
            this.MouseClick += this.OnMouseClick;
        }

        private void OnMouseClick(object sender, MouseEventArgs e)
        {
            throw new Exception("Hey! That hurts!");
        }
    }
}
使用系统;
使用System.Windows.Forms;
命名空间Windows窗体应用程序1
{
静态类程序
{
/// 
///应用程序的主要入口点。
/// 
[状态线程]
静态void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(新Form1());
}
}
公开课表格1:表格
{
公共表格1()
{
this.MouseClick+=this.OnMouseClick;
}
鼠标单击时的私有void(对象发送者,鼠标目标)
{
尝试
{
var f2=新的Form2();
f2.显示对话框(本);
}
catch(System.Exception-ex)
{
MessageBox.Show(例如消息“异常捕获!”,
MessageBoxButtons.OK,MessageBoxIcon.Information
);
}
}
}
公开课表格2:表格
{
公共表格2()
{
this.MouseClick+=this.OnMouseClick;
}
鼠标单击时的私有void(对象发送者,鼠标目标)
{
抛出新的异常(“嘿!太痛了!”);
}
}
}

这是64位窗口的一种行为:表单的加载或显示事件中发生的异常会被吞没。可以在

中找到一个很好的解释,它可以帮助您调试未处理的异常。ShowDialog()是特殊的,在关闭对话框之前,该方法不会返回。它通过启动另一个dispatcher循环(与Application.Run()完全等效)而成为模态

由dispatcher循环(事件处理程序)激活的代码引发的异常通过Application.UnhandledException事件报告。这种行为严重阻碍了调试仍然不稳定的代码。调试器没有理由介入并向您展示代码是如何爆炸的,因为异常实际上是被处理的。通过引发事件来处理。所以,特殊的规则是,如果附加了调试器,那么dispatcher循环将不会捕获异常并引发事件

现在你的catch子句起作用了。但只有在进行调试时,它才能在没有调试的情况下工作,也不能在用户的机器上工作

通过修改Main()方法,将
UnhandledExceptionMode.ThrowException
传递给Application.SetUnhandledExceptionMode(),可以更改此行为。这通常是一个明智的做法,因为默认的事件处理程序相当蹩脚。它让用户决定是否继续运行程序,用户几乎永远不知道正确的选择。您希望为AppDomain.CurrentDomain.UnhandledException编写事件处理程序,以便正确报告每个未处理的异常,包括在工作线程中引发的异常。像这样:

    [STAThread]
    static void Main() {
        if (!System.Diagnostics.Debugger.IsAttached) {
            Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException);
            AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
        }
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new Form1());
    }

    private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) {
        MessageBox.Show(e.ExceptionObject.ToString());
        // Workaround for Windows 10.0.10586 bug:
        AppDomain.CurrentDomain.UnhandledException -= CurrentDomain_UnhandledException;
        Environment.Exit(1);
    }

该条款值得特别提及。你真的不必在意对话框没有像那样使用catch-em-all异常处理。让用户非常困惑的是,窗口无缘无故消失了。而且很可能会让你的程序很混乱,你也会抓到一些非常讨厌的东西。小心调试这个异常会带来的麻烦。您需要调试>Windows>异常设置>勾选“公共语言运行时异常”,以便在引发异常时强制调试器停止。

我测试了此解决方案,效果良好。谢谢你的透彻解释,它非常有意义。一篇有趣的文章和一篇引人入胜的阅读。我认为它不太适用于这种情况,在“onload”期间不会抛出异常。