【问题标题】:Try Catch Throw尝试接球
【发布时间】:2012-07-30 09:29:26
【问题描述】:

我正在尝试了解如何在我的代码中使用 Throw。我有一个 MainForm 类来处理 Windows 窗体 GUI,然后我有一个 Manager 类来读取和保存文件中的数据。

我在两个课程中都使用 Try/Catch,但我的导师希望我在 Manager 课程中使用 Throw,尽管我正在阅读它,但我不明白它会做什么? Throw 会影响 MainForm 类中的 Try/Catch 吗?

如果捕获到异常,我也会在管理器类中使用消息框,但是根据讲师的说法,管理器中不允许出现消息框,那我该怎么办?我可以只在 MainForm 类中使用消息框吗?对理解和扩展我的知识有一些帮助!谢谢!

MainForm 类:

try
{
     motelManager.SaveToFile(file);
}
catch
{
     MessageBox.Show("Ett fel uppstod!", "Varning!", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
}

经理类:

 public void SaveToFile(string filePath)
 {
     try
     {
         string newFilePath = filePath.Replace(".bin", "");
         filestream = new FileStream(newFilePath + ".bin", FileMode.Create);
         BinaryFormatter b = new BinaryFormatter();
         b.Serialize(filestream, animals);
     }
     catch(Exception ex)
     {
         MessageBox.Show(ex.Message, "Varning!", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
     }

     if (filestream != null) filestream.Close();
 }

【问题讨论】:

  • 这段代码让我担心,它看起来像一个文件路径被传入并且一个流被打开到一个全局变量,那么如果有一个问题你要调用关闭,如果你关闭了你的filestream 如果不重新分配,您将无法重新打开它,在这种情况下,此代码不好,因为它总是会关闭它。您应该在此处使用“使用”块在调用 close 后调用 dispose。

标签: c# .net


【解决方案1】:

你的经理类应该是这样的:

public void SaveToFile(string filePath)
{
    try
    {
        string newFilePath = filePath.Replace(".bin", "");
        filestream = new FileStream(newFilePath + ".bin", FileMode.Create);
        BinaryFormatter b = new BinaryFormatter();
        b.Serialize(filestream, animals);
    }
    catch(Exception ex)
    {
        if (filestream != null) filestream.Close();
        throw;
        // but don't use
        // throw ex;
        // it throws everything same
        // except for the stacktrace
    }
    // or do it like this
    //catch(Exception ex)
    //{
    //    throw;
        // but don't use
        // throw ex;
        // it throws everything same
        // except for the stacktrace
    //}
    //finally
    //{
    //    if (filestream != null) filestream.Close();
    //}

}

在你的主课中:

try
{
    motelManager.SaveToFile(file);
}
catch (Exception e)
{
    MessageBox.Show("Ett fel uppstod!", "Varning!", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
}

【讨论】:

  • 嗯,但是 Throw 有什么作用?
  • 你应该把文件流放在使用中,而不是在catch中明确关闭它。
  • 它会抛出当前异常
  • 它捕获并向main 类抛出相同的异常。它被称为异常的rethrowing
  • 啊哈!就像我当时想的一样!不错!
【解决方案2】:

Throw 只是将异常引发到调用函数。 (在这种情况下,无论谁调用 SaveToFile)。如果那里有错误处理程序,它将被捕获,否则它将继续调用堆栈,直到它被捕获或在顶层。

【讨论】:

    【解决方案3】:

    最好处理表单中向用户呈现的异常——因为在一个结构良好的大型系统中,Manager 对象可能与 GUI 没有任何连接。

    一般规则是在后端 [Manager] 类中捕获异常以清理所有资源(即关闭文件),然后从异常处理程序中重新抛出异常,如下所示:

    public void SaveToFile(string filePath)
    {
        try
        {
            string newFilePath = filePath.Replace(".bin", "");
            filestream = new FileStream(newFilePath + ".bin", FileMode.Create);
            BinaryFormatter b = new BinaryFormatter();
            b.Serialize(filestream, animals);
        }
        catch(Exception ex)
        {
            /* 
             * cleanup resources and rethrow the exception for catching and handling elsewhere
             */
            if (filestream != null)
                filestream.Close();
            throw;
        }
    
    }
    

    【讨论】:

      【解决方案4】:
      public void SaveToFile(string filePath)
      {
          try
          {
               string newFilePath = filePath.Replace(".bin", "");
               filestream = new FileStream(newFilePath + ".bin", FileMode.Create);
               BinaryFormatter b = new BinaryFormatter();
               b.Serialize(filestream, animals);
          }
          catch (Exception ex)
          {
              if (filestream != null) filestream.Close();
              //what you want
              //MessageBox.Show(ex.Message, "Warning!");
              throw (new Exception("Your custom message"));
          }
      }
      

      在你的经理中:

      try
      {
          manager.SaveToFile(filePath);
      }
      catch (Exception ex)
      {
          // here shows your 'Your custom message'
          MessageBox.Show(ex.Message);
      }
      

      【讨论】:

        【解决方案5】:

        在具有多个层的应用程序中,底层发生的异常不会按原样发送到更高层或调用应用程序。

        例如,如果数据库相关代码出现问题,您不会将其发送到客户端应用程序或更高层。这样做的原因是为用户提供友好的错误消息。比如说,你在删除操作时出现了外键引用错误,你可以:

        1. 记录异常信息。
        2. 替换为用户友好的异常消息并将其扔到上层。

        上面的层可能会将此异常包装到另一个更高级别的消息中,然后将其抛出。这类似于您被要求做的事情。

        在 Manager 类的代码中,检查可能发生多少异常。如果您使用的是 VS,则工具提示/帮助文本会提供该信息。如果您不使用 VS,请查看 MSDN 以获取此信息。

        在表单中,处理所有可能由管理层抛出的异常,以及如果发生严重错误时的通用异常。恕我直言,这就是你的管理层代码应该是这样的

        try
                    {
                        string newFilePath = filePath.Replace(".bin", "");
                        FileStream filestream = new FileStream(newFilePath + ".bin", FileMode.Create);
                        BinaryFormatter b = new BinaryFormatter();
                        b.Serialize(filestream, animals);
                    }
                    catch (ArgumentNullException argNullException)
                    {
                        // Log current exception
        
                        // Wrap it under your exception type
                        CustomWrapException customWrap = new CustomWrapException();
                        customWrap.Message = "Your custom message here.";
                        customWrap.InnerException = argNullException;
                        throw customWrap;
                    }
                    catch (SecurityException securityException)
                    {
                        // Log current exception
        
                        // Replace current exception with you custom exception
                        CustomReplaceException replaceException = new CustomReplaceException();
                        replaceException.Message = "Your custom message here.";
                        throw replaceException;
                    }
                    finally
                    {
                        // Close stream and dispose objects here
                    }
        

        你的表单应该有这样的异常处理:

        try
                    {
                        // Call mananger code from here
                    }
                    catch (CustomWrapException wrapException)
                    {
                        // replace/wrap if desired
                        // Display message to user
                    }
                    catch (CustomReplaceException replaceException)
                    {
                        // replace/wrap if desired
                        // Display message to user
                    }
                    catch (Exception exception)
                    {
                        // This is for everything else that may go wrong apart from known possible exceptions
                        // Display message to user
                    }
                    finally
                    {
        
                    }
        

        HTH。

        【讨论】:

        • 写这篇文章的上下文是正确的,但是在替换原始异常时应该非常小心,如果在层之间它还可以..但如果不是它就有点不行了
        • @krystanhonour 完全同意。
        【解决方案6】:

        您可以使用Application ThreadException 来捕获任何异常。并且你的保存逻辑用 using 而不是 try catch 来包装,在这种情况下它将关闭你的流。

        public void SaveToFile(string filePath)
        {
            string newFilePath = filePath.Replace(".bin", "");
            using(var filestream = new FileStream(newFilePath + ".bin", FileMode.Create))
            {
                BinaryFormatter b = new BinaryFormatter();
                b.Serialize(filestream, animals);
            }
        }
        

        在入口点 (static void main()) 订阅此事件。

            [STAThread]
            static void Main()
            {
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
                Application.Run(new Form1());
        
                Application.ThreadException += Application_ThreadException;
            }
        
            static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e)
            {
                MessageBox.Show(".......");
            }
        

        【讨论】:

        • 如果您传递了无效的字符串格式,如{ } * 等怎么办?
        • 这是危险代码,您可能会在全局范围内调用 dispose,真正的问题不是此代码,而是文件流在全局范围内声明......不是 Artioms 错误...... . 将文件流移动到本地范围以避免出现问题。
        【解决方案7】:

        原来是这样的……

         try { } 
        catch(Exception e) 
        { throw } 
        

        当它抛出异常时,它会改变源和堆栈跟踪,因此看起来异常已经从这个方法中抛出,从包含该 try-catch 块的方法上的那一行 throw e 开始。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2016-05-11
          • 2018-07-17
          • 2016-06-20
          • 1970-01-01
          • 1970-01-01
          • 2016-07-18
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多