C# Windows窗体应用程序中异常处理的最佳实践?

C# Windows窗体应用程序中异常处理的最佳实践?,c#,winforms,exception-handling,C#,Winforms,Exception Handling,我目前正在编写我的第一个Windows窗体应用程序。我现在已经读了一些C#的书,所以我对C#必须处理异常的语言特性有了比较好的理解。然而,它们都是理论性的,所以我还没有感觉到如何在我的应用程序中将基本概念转换为一个好的异常处理模型 有人愿意分享关于这个问题的智慧吗?发布像我这样的新手所犯的任何常见错误,以及处理异常的一般建议,以使我的应用程序更加稳定和健壮 我目前正在努力解决的主要问题是: 我应该在什么时候重新抛出异常 我是否应该尝试使用某种中央错误处理机制 与先发制人地测试磁盘上是否存在文件

我目前正在编写我的第一个Windows窗体应用程序。我现在已经读了一些C#的书,所以我对C#必须处理异常的语言特性有了比较好的理解。然而,它们都是理论性的,所以我还没有感觉到如何在我的应用程序中将基本概念转换为一个好的异常处理模型

有人愿意分享关于这个问题的智慧吗?发布像我这样的新手所犯的任何常见错误,以及处理异常的一般建议,以使我的应用程序更加稳定和健壮

我目前正在努力解决的主要问题是:

  • 我应该在什么时候重新抛出异常
  • 我是否应该尝试使用某种中央错误处理机制
  • 与先发制人地测试磁盘上是否存在文件相比,处理可能引发的异常是否会影响性能
  • 所有可执行代码是否都应该包含在try-catch-finally块中
  • 是否有任何时候可以接受空的catch块

所有的建议都收到了,非常感谢

例外是昂贵的,但却是必要的。您不需要将所有内容都封装在一个try-catch中,但您确实需要确保最终总是捕获异常。这在很大程度上取决于你的设计

如果让异常上升也可以,请不要重新抛出。 不要让错误不知不觉地过去

例如:

void Main()
{
  try {
    DoStuff();
  }
  catch(Exception ex) {
    LogStuff(ex.ToString());
  }

void DoStuff() {
... Stuff ...
}

如果多斯塔夫出了问题,你无论如何都会希望它保释。异常将被抛出main,您将在ex的堆栈跟踪中看到一系列事件。

我喜欢不捕获我不打算处理的任何内容的哲学,不管在我特定的上下文中处理意味着什么

我讨厌看到这样的代码:

try
{
   // some stuff is done here
}
catch
{
}
我经常看到这种情况,当有人“吃”异常时,很难发现问题。我的一位同事做了这件事,结果往往会导致一系列问题

如果我的特定类需要做一些事情来响应异常,但是问题需要被冒泡出来,不管它发生在什么地方,我都会重新抛出


我认为代码应该是主动编写的,异常应该针对异常情况,而不是为了避免条件测试。

我正要退出,但将简要介绍在何处使用异常处理。当我返回时,我将尝试解决您的其他问题:)

  • 显式检查所有已知的错误条件*
  • 如果您不确定是否能够处理所有情况,请在代码周围添加try/catch
  • 如果正在调用的.NET接口引发异常,请在代码周围添加try/catch
  • 如果代码超过复杂度阈值,请在代码周围添加try/catch
  • 如果要进行健全性检查,请在代码周围添加try/catch:您断言这种情况永远不会发生
  • 作为一般规则,我不使用异常替换返回代码。这对.NET很好,但对我来说不是。不过,我确实有例外(呵呵),这也取决于您正在处理的应用程序的体系结构
  • *在合理的范围内。不需要检查是否有宇宙射线击中了你的数据,导致一些比特被翻转。 理解什么是“合理的”是工程师必须掌握的技能。这很难量化,但很容易凭直觉判断。也就是说,我可以很容易地解释为什么我在任何特定的情况下使用try/catch,但我很难向其他人灌输同样的知识

    我个人倾向于避开严重基于异常的体系结构。try/catch本身不会对性能产生影响,当抛出异常时会产生影响,代码可能需要在调用堆栈的多个级别上运行,然后才能进行处理

    我应该在什么时候重新抛出异常

    无处不在,但最终用户方法。。。像按钮点击处理程序

    我是否应该尝试使用某种中央错误处理机制

    我写了一个日志文件。。。对于WinForm应用程序来说非常简单

    与先发制人地测试磁盘上是否存在文件相比,处理可能引发的异常是否会影响性能

    我不确定这一点,但我相信这是一个很好的做法,认为例外。。。我的意思是,您可以询问文件是否存在,以及它是否没有抛出FileNotFoundException

    所有可执行代码是否都应该包含在try-catch-finally块中

    是否有任何时候可以接受空的catch块


    是的,假设您想显示一个日期,但您不知道该日期是如何存储的(dd/mm/yyyy、mm/dd/yyyy等),您尝试tp解析它,但如果失败,请继续。。。如果这与你无关。。。我会说是的,有一件事我很快就学会了,那就是用try-catch块将与我的程序流(即文件系统、数据库调用、用户输入)之外的任何东西进行交互的每一块代码都封装起来。Try-catch可能会导致性能下降,但通常在代码中的这些地方,它不会引起注意,并且会为自己的安全付出代价。

    我在用户可能会做一些并非真正“不正确”的事情的地方使用了空catch块,但它可能引发异常…我想到的一个例子是在GridView中,如果用户双击左上角的灰色占位符单元格,它将触发CellDoubleClick事件,但该单元格不属于某一行。在这种情况下,您实际上不需要发布消息,但如果您没有捕获到它,它将向用户抛出一个未处理的异常错误

    有一个很好的代码。以下是几个亮点:

    • 做最坏的打算*
    • 早点检查
    • 不要相信外界
      throw ex;
      
      throw;
      
      Try
      {
      int a = 10 / 0;
      }
      catch(exception e){
      //error logging
      throw;
      }
      
      catch(Exception e)
      // logging
      throw e;
      }
      
      try
      {
         dict.Add(key, value);
      }
      catch(KeyException)
      {
      }
      
      if (!dict.ContainsKey(key))
      {
         dict.Add(key, value);
      }
      
      try
      {
      /*Doing stuff that may cause an exception*/
      Response.Redirect("http:\\www.somewhereelse.com");
      }
      catch (ThreadAbortException tex){/*Ignore*/}
      catch (Exception ex){/*HandleException*/}
      
      using System.Threading;
      
      Application.ThreadException += new ThreadExceptionEventHandler(Application_ThreadException);
      
      static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
      {
          // Do logging or whatever here
          Application.Exit();
      }