【问题标题】:Handling of unforseen exceptions处理不可预见的异常
【发布时间】:2015-03-25 10:32:14
【问题描述】:

如果我想写入文件并处理IOExceptions(以防文件被写保护),我会执行以下操作:

try
{
    var fs = new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.None);
    using (StreamWriter sw = new StreamWriter(fs, Encoding.Default)
    {    
        sw.WriteLine(entry);
    }
}
catch (IOException ex)
{
    return ex.Message;
}

如果我遇到意外的异常,我的程序会崩溃,用户会报告错误,我会修复它。这就是我想要的。

所以我应该添加另一个捕获,例如:

catch (Exception)
{
    throw;
}

这会有什么不同吗?最佳做法是什么?

【问题讨论】:

    标签: c# exception try-catch


    【解决方案1】:

    您应该处理意外的异常,但是带有 throw 的 catch 是多余的 - 无论如何都会从您的方法中抛出异常。你应该做的是问自己一个问题,“我能对这个异常做些什么?”。对于IOException,答案很明确。您期望异常可能发生、可以处理并且可以继续。对于通用Exception,这可能不是处理它的地方。

    如果您需要在发生异常时运行某些代码,请为其添加catch。如果您的代码在该异常之后无法继续,请将异常抛出更高(不处理它或使用throw),并在调用层次结构中添加更高的处理程序。也许它可以在更高的层次上处理,并且可以继续执行。如果没有,您的应用程序将需要退出。

    您可以在程序的入口点添加顶级try/catch 块,并在那里捕获未处理的异常。您的应用程序甚至可以在此之后继续(但是,考虑到此时抛出的异常有多高,在任何非平凡的应用程序中都不太可能)。要捕获任何其他未处理的异常(例如,在线程中未处理的异常),您可以将处理程序添加到 AppDomain.CurrentDomain.UnhandledException。但是,这是不可恢复的——您的应用程序将在之后直接退出。 UnhandledException 处理程序是在异常发生之前做某事的最后机会,通常记录它以诊断出了什么问题。

    哦,另外,如果您正在编写 WPF 应用程序,您可以在 App.xaml 中为Application 上的DispatcherUnhandledException 事件添加一个处理程序。这会捕获 WPF 调度程序线程中发生的任何未处理的异常。与上面的 AppDomain 处理程序不同,调度程序线程上未处理的异常可以从以下位置继续 - 如果应用程序可以继续,您可以将事件参数中的 IsHandled 设置为 true。

    【讨论】:

      【解决方案2】:

      所以我应该添加另一个像

      (几乎)从不。至少不在堆栈跟踪中。它只会使您的应用程序更难阅读。

      大多数应用程序都有入口点。例如,如果您编写 Windows 服务,您通常会为工作创建线程。您可以在其中添加catch (Exception) 以防止它们崩溃。

      所以我的意思是,在大多数情况下,您应该只在顶层使用 catch all 以防止您的应用程序难以阅读或维护。

      当一切都失败时

      有时,如果您在顶层某处忘记了全部捕获,那么您的应用程序无论如何都会崩溃。

      然后您想使用AppDomain.UnhandledException,因为它在.NET 中的所有应用程序类型中都被调用。但是,它不会让您阻止应用程序崩溃,而只是记录您的应用程序即将崩溃的原因。

      如果您正在编写基于 winforms 的 UI 应用程序,您可以改用 Application.ThreadException。但是,它只会处理 UI 线程上的异常。因此,您仍然需要使用AppDomain.UnhandledException 来记录其他线程上抛出的异常。

      .NET 中的所有主要库/框架都有自己的方式来处理未处理的异常。您需要在您正在使用的库的文档中查找它。

      【讨论】:

      【解决方案3】:

      您可以使用AppDomain.UnhandledException 事件。

      也许您也想使用Application.ThreadException 事件。

      【讨论】:

        【解决方案4】:
        catch(Exception)
        { 
        
            throw;    
        } 
        

        什么都不做。异常与它的原始堆栈跟踪一起引发,并且不执行任何其他操作。您可以捕获一般异常,这使您可以选择提供额外的日志记录和/或向用户显示更好的错误消息

        catch(Exception ex)
        { 
            LogError(ex);
            if (weDontCareThisWasntImportantAnyWay)
            {
                if (theUserShouldBeNotifiedAtThisPoint)
                {
                    SomehowNotifyTheUser(ex);
                }
            }
            else
            {
                //Maybe something else cares
                throw;    
            }
        } 
        

        【讨论】:

          【解决方案5】:

          嗨,如果你想抛出应用程序崩溃的异常,请这样做

           try
          {
              var fs = new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.None);
              using (StreamWriter sw = new StreamWriter(fs, Encoding.Default)
              {    
                  sw.WriteLine(entry);
              }
          }
          catch (IOException ex)
          {
              throw ex;
          }
          

          但我认为你不应该让它崩溃而只显示错误消息

          在 catch 调用函数中写入文件,然后返回消息并显示给用户。希望对你有帮助

           public static void WriteCustomLog(string msg)
                      {
                          FileStream fs = null;
                          StreamWriter sw = null;
                          FileStream fs1 = null;
                          StreamWriter sw1 = null;
                          try
                          {
                              //check and make the directory if necessary; this is set to look in the application
                              //folder, you may wish to place the error log in another location depending upon the
                              //the user's role and write access to different areas of the file system
                              if (!System.IO.Directory.Exists(Application.StartupPath + "\\Log\\"))
                                  System.IO.Directory.CreateDirectory(Application.StartupPath + "\\Log\\");
          
                              string date = DateTime.Now.ToString("dd_MM_yyyy");
          
                              //check the file
                              fs = new FileStream(Application.StartupPath + "\\Log\\Log" + date + ".txt", FileMode.OpenOrCreate, FileAccess.ReadWrite);
                              sw = new StreamWriter(fs);
                              sw.Close();
                              fs.Close();
          
                              //log it
                              fs1 = new FileStream(Application.StartupPath + "\\Log\\Log" + date + ".txt", FileMode.Append, FileAccess.Write);
                              sw1 = new StreamWriter(fs1);
                              sw1.Write(DateTime.Now.ToString() + " Message: " + msg + Environment.NewLine);
                              sw1.Write("Date/Time: " + DateTime.Now.ToString() + Environment.NewLine);
                              sw1.Write("=======================================================" + Environment.NewLine);
          
                          }
          }
          

          然后处置对象 没测试过

          【讨论】:

          • 我不希望应用程序在 IOException 上崩溃,因为这可能会发生并因此处理它。它是关于我不例外的例外。我应该抓住它们然后扔掉还是什么都不做。
          • 所以返回异常中的消息显示给用户,并编写带有错误的自定义日志(返回 ex.Message;)
          • 这会重置堆栈跟踪
          【解决方案6】:

          您可以捕获异常,然后在内部检查异常是什么类型。然后决定如何处理。

          catch(Exception ex)
          {
            if(ex.InnerException is IOException )
            {
              // do  something
            }
           else
            {
             // do something else
            }
          }
          

          【讨论】:

          • 为什么?你可以只 catch(IOException) 然后通过链接处理程序来回退到 Exception()。
          • @kha:你没注意到他检查了 INNER 异常。你听不懂。
          • @jgauffin 问题是关于捕获 IOException 和调用方法时可能发生的其他类型的异常,这个答案是检查捕获所有异常的内部异常作为一种方法。这种方法是错误的:不是每个异常都有一个 InnerException 并且不是每个 IOException 都被重新抛出(事实上,如果它是重新抛出 IOException 的标准行为,我会感到惊讶),这意味着这个解决方案不会处理一个 IOException 是异常的原因,而不是作为具有 IOException 对象的 InnerException 的另一种类型的异常重新抛出。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-12-16
          • 2021-11-20
          • 2011-02-07
          • 2012-05-14
          相关资源
          最近更新 更多