【问题标题】:Can't catch exception thrown in FormClosing无法捕获 FormClosing 中引发的异常
【发布时间】:2013-12-14 06:31:54
【问题描述】:

当在 FormClosing 中抛出异常时,我无法通过正常的 try/catch 捕获它 - 为什么不呢?

例子:

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

    protected override void OnClosing(CancelEventArgs e)
    {
      base.OnClosing(e);
      throw new Exception("lets catch this");
    }
  }

我试着像这样抓住它:

  try
  {
    var f = new Form2();
    f.ShowDialog();
  }
  catch (Exception ex)
  { 
    //this is never hit!
    MessageBox.Show("try/catch: " + ex);
  }

抛出异常,只是从未在我的 try/catch 中捕获。

可以,但是,使用Application.ThreadException += .. 捕获它,但此时很难恢复。

我能做什么?

另外:
我正在使用 Windows8 x64 - 该程序具有目标平台 x86
我发现了一个与我的here 很接近的问题,但我的异常并没有沉默。

更新 1
当我附加到进程时,它会像我刚刚手动启动 .exe 文件一样失败:

【问题讨论】:

  • 程序有时在启动调试 (F5) 和正常启动后由调试器附加 (Ctrl+F5) 时的行为会有所不同。如果附加到进程会发生什么?
  • 是模态对话框吗?
  • @helb 是 - ShowDialog 是模态的
  • @Dialectus 它显然抛出了一个未处理的异常......更新我的问题
  • 你能在一些 32 位 Windows 上测试这个程序吗?另外,在一些较旧的 Windows 上?如果更改目标平台会发生什么?

标签: winforms visual-studio-2010 c#-4.0 exception-handling


【解决方案1】:

这是预期的行为。

ShowDialog 方法不应该抛出它的事件抛出的异常。你所做的也是错误的方法。您对OnClosing 的覆盖应该是安全的,不会引发任何错误。如果不是这种情况,则会作为 UnhandledException 传递。

可以捕获异常,但您应该在 OnClosing 处理程序中进行。

protected override void OnClosing(CancelEventArgs e)
{
  base.OnClosing(e);
  try {
    throw new Exception("lets catch this");
  }
  catch (Exception e) {
    // Do something with e
  }
}

负责此行为的代码被剥离如下:

  try
  {
    FormClosingEventArgs e1 = new FormClosingEventArgs(this.closeReason, false);
    this.OnClosing((CancelEventArgs) e1);
    this.OnFormClosing(e1);
  }
  catch (Exception ex)
  {
    Application.OnThreadException(ex);
  }

您的问题的解决方案可能是这样的:

public partial class Form2 : Form
{
    // I'm using the event here, but if this class in turn is a base for another class, you might as well override the method. (Event will still work, since events allow multiple handlers when using the default event handlers.)
    private void Form2_FormClosing(object sender, FormClosingEventArgs e)
    {
        try
        {
            // Action that might throw an exception
            throw new Exception("Some exception");
        }
        catch (Exception ex)
        {
            OnClosingException = ex;
        }
    }

    public Exception OnClosingException { get; protected set; }
}

// When calling
var f = new Form2();
f.ShowDialog();
if (f.OnClosingException != null) // Re-throw the exception wrapped in another exception that describes the problem best
    throw new InvalidOperationException("Some message", f.OnClosingException); // Might not always be InvalidOperationException
// Instead of re-throwing you can also just handle the exception

如果这是您计划在很多场景中使用的东西,您可能希望为此创建一个界面,以便以良好的结构化方式将其全部包装起来。对于一次性场景,我不会打扰。

【讨论】:

  • 为什么要用 try-catch 包装所有事件处理程序?为什么不将异常保存在OnThreadException 事件处理程序中?
  • @Dialecticus 因为原版发帖人要抓?另一个原因是好的设计。未处理的事件表明代码存在问题,因为这是您不期望的。如果您希望某个方法抛出异常,您可以捕获它,并优雅地从中恢复。未处理的异常通常意味着您无法安全恢复并仍处于可靠状态。您不应该用 try-catch 包装每个事件处理程序,只有当您期望可以处理的异常时。但是,当 触发 事件时,通常最好始终将其包装在 try-catch 中。
  • 我不知道其他程序员对此有何感想,但我真的很想用一个 catch 来捕捉所有 unexpected 异常,在这个 catch-all 中我最想可能只是通知用户和/或在日志文件中写入异常。应用程序处于故障状态的可能性非常低,但即便如此,用户也会收到警告。我真的不想用 try-catch 包装所有事件处理程序来覆盖那些 unexpected 异常。
  • 我觉得 exacly 就像@Dialectus - 因为我不想将每个事件处理程序都包装在“generel”try/catch 中。话虽如此 - @Aidiakapi 回答了我的问题,并解释了为什么我不能像我想要的那样捕获异常。但是为什么直接去Application.OnThreadException(ex)而不是直接抛出异常更好呢?
  • 我说那个代码是负责该行为的代码。它由 System.Windows.Forms.Form 类定义。如果您不想要一般的 try catch 语句,为什么该语句在您的示例代码中。 This article 很好地解释了异常的类型,以及您应该如何处理它们。我不知道您在哪里读到我的建议,即在每个事件处理程序周围放置一个通用的 try-catch。这不在我的回答中,我的“解决方案”是您在问题中提供的代码的镜像。
猜你喜欢
  • 2013-02-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-19
  • 2019-09-13
  • 1970-01-01
  • 2011-10-04
相关资源
最近更新 更多