【问题标题】:try-catch blocks with the return type具有返回类型的 try-catch 块
【发布时间】:2010-10-10 19:16:13
【问题描述】:

如果我有一个返回某些东西的方法,比如

public DataTable ReturnSomething()
{
   try
   {  
      //logic here
     return ds.Tables[0];
   }
   catch (Exception e)
   {
      ErrorString=e.Message;
   }
}

这会产生编译器错误,显然是因为catch{} 块没有返回任何内容。

所以当我有返回值的方法时,我不使用 try-catch 块,这是一种不好的做法。如果有错误,我想将错误字符串设置为该错误。但是我也需要一个返回值。建议?

【问题讨论】:

  • “所以当我有返回值的方法时,我不使用 try-catch 块,这是一种不好的做法。”谁说的?大多数方法返回值而不被包装在 try 块中。
  • 被打败了20秒!确实,正是我要说的;如果有异常——除非你期望它并且可以做一些有用的事情,让它冒泡给调用者。
  • 吞下异常是真正的问题。

标签: c# error-handling


【解决方案1】:

你可以像下面的示例代码那样做。

public DataTable ReturnSomething(out string OutputDesc)
{
   try
      {
         //logic here
         OutputDesc = string.Format("Your Successful Message Here...");
         return ds.Tables[0];
      }
      catch (Exception e)
      {
         OutputDesc =e.Message;
         return null;
      }

}

【讨论】:

    【解决方案2】:

    您应该在 catch 块中引发/抛出异常并在调用方法中处理它。

    public void invokeFaultyCode()
    {
        try
        {
            DataTable dt = ReturnSomething();
        }
        catch(Exception e)
        {
            // Print the error message, cleanup, whatever
        }    
    }
    public DataTable ReturnSomething() throws Exception
    {
       try
       {  
          //logic here
         return ds.Tables[0];
       }
       catch (Exception e)
       {
          ErrorString=e.Message;
          throw;
       }
    }
    

    PS:抱歉有任何语法错误,我对 C# 有点生疏了。

    【讨论】:

    • 你可能只想抛出,因为 throw e 会改变异常堆栈。
    • 请注意;将throws 附加到方法上是.NET 中不存在的Java 概念。
    • AM 在返回方法上收到此错误 ArgumentOutOfRange 异常:public string GetUserName() { List<LoginModel> list = _connection.Query<LoginModel>("Select username From [LoginModel] where ID=1"); string username = null; try { username = list[0].username; return username; } catch(ArgumentOutOfRangeException e){ } catch (Exception e) { } return username; }
    • 这会编译吗? CATCH 块中没有返回任何内容。
    【解决方案3】:

    你应该用 try catch 包裹调用者...在被调用的例程中发生的任何异常都会冒泡到调用者那里,你可以在那里捕获它们。

    就我个人而言,我认为在此例程中使用 try catch 有点过头了,因为您应该让调用者处理异常。

    对于我的例子,这将被编码如下......

    private void DoSomething() {
        try {
            DataTable dt = ReturnSomething();
        }
        catch (Exception ex) {
        }    
    }
    
    public DataTable ReturnSomething() {
        DataTable dt = new DataTable();
    
        // logic here
        return dt;
    }
    

    【讨论】:

      【解决方案4】:

      ErrorString 变量看起来很像错误代码变量。推荐的做法是在必要时使用异常直接传递错误信息,而不是将内容存储到错误代码中。

      您实际上是在对 ErrorString 做同样的事情,就像您只是让调用者捕获异常一样:从方法本身移除响应错误的责任。这是一个很好的目标。但是使用错误字符串不会比使用异常获得任何好处。事实上,您会以这种方式丢失信息。可能会发生多种类型的错误,并且许多都有与之相关的特殊异常,它们具有自己的特殊属性来保存有关故障的上下文信息。仅将消息存储在字符串中,您将丢失此信息。

      因此,除非您的目标是专门向调用者隐藏正在发生的错误类型,否则您只能通过让异常通过来获得收益。

      要考虑的另一件事是这是否真的是一个错误场景。如果是,那么您的调用方法就不太可能关心返回值是什么。在这种情况下,您无需担心,只需让异常消失而不返回任何内容。如果这不是一个真正的错误场景,而调用者只是继续做其他事情,那么那是由调用者决定的,对吧?通过返回错误字符串和虚拟 DataTable 或 null 来获得仍然没有太多好处,而不是抛出带有所有上下文失败信息的异常。

      【讨论】:

        【解决方案5】:

        如果您打算采用“不要抛出异常路线”(我不一定推荐),您可以遵循 MS 使用的 TryParse 方法。

        类似:

        private string FillDataTable(out DataTable results)
        {
        
          try
        {
          results = new DataTable(); //something like this;
          return String.Empty;
        }
        catch (Exception ex)
        {
          results = null;
         return ex.Message;
        
        }
        

        }

        【讨论】:

          【解决方案6】:

          这个怎么样:

          public DataTable ReturnSomething(out string errorString)
          {
             errorString = string.Empty;
             DataTable dt = new DataTable();
             try
             {  
                //logic here
               dt = ds.Tables[0];
             }
             catch (Exception e)
             {
                errorString = e.Message;
             }
             return dt;
          }
          

          【讨论】:

          • 不会是编译器错误吧,因为errorString是个out,不保证会设置?
          • 是的,你说得对,我只是在 SO 编辑器中写的 :) 编辑!
          • @ScarletGarden:我做同样的事情;]
          【解决方案7】:

          我假设您仍然可以设置消息,然后返回 null 或任何 c# 等效项

          public DataTable ReturnSomething(){ 
             try {
                  //logic here 
                  return ds.Tables[0]; 
             } catch (Exception e) {
                  ErrorString=e.Message;
                  return null;
             }
          }
          

          【讨论】:

            【解决方案8】:

            由于您在示例中捕获异常(而不是再次抛出),因此外部代码假定一切正常,因此您应该返回一些有用的东西。

            如果您需要在此处捕获异常并执行某些操作,这一切都很好,但如果它仍然是一个错误情况,您也应该抛出它,或者一个不同的异常,也许是您刚刚捕获为 InnerException 的那个。

            【讨论】:

              【解决方案9】:

              我认为您的代码在调用堆栈的足够高级别上运行,并且与 UI 代码混合在一起。如果确实如此,您可以在 catch 块中使用return null。但是,如果您正在编写可重用代码,则应重构它,使其不包含 UI 操作并在调用堆栈中的更高级别处理异常。

              【讨论】:

                【解决方案10】:

                将您的返回值存储在一个临时变量中,如下所示:

                public DataTable ReturnSomething()
                {
                    DataTable returnValue = null;
                
                    try
                    {
                        //logic here
                        returnValue = ds.Tables[0]; 
                    }
                    catch (Exception e)
                    {
                        ErrorString=e.Message;
                    }
                
                    return returnValue;
                }
                

                【讨论】:

                • 就像其他人指出的那样,您应该考虑抛出异常而不是设置 ErrorString。如果你想要一个带有你自己的消息的异常,你应该抛出一个新的异常,将原始异常作为内部异常。 throw new ArgumentException("我的消息", e);
                • 我同意 Svish 和其他人的观点;尽管我已尝试按要求回答您的问题,但我认为这不是解决您问题的最佳方法。
                【解决方案11】:

                这取决于您的应用程序。您可以返回 null、空的 DataTable 或任何适合的情况。

                【讨论】:

                • 这完全取决于具体情况。您应该始终问这样一个问题:“如果这里发生异常,这意味着什么?”而不是遵循同样的死记硬背的做法。拥有异常处理程序的部分原因是为了处理异常。
                猜你喜欢
                • 1970-01-01
                • 2014-04-30
                • 2012-05-18
                • 2016-05-06
                • 2015-07-07
                • 2019-08-31
                • 2016-02-01
                • 1970-01-01
                • 2021-12-25
                相关资源
                最近更新 更多