【问题标题】:C# Exception Handling Fall Through [duplicate]C#异常处理失败[重复]
【发布时间】:2010-12-18 01:43:54
【问题描述】:

可能重复:
Catch multiple Exceptions at once?

在C#中有什么方法可以轻松实现以下伪代码:

try
{
...
}
catch ( ExceptionTypeA, ExceptionTypeB, ExceptionTypeC as ex)
{
... same code for all threw
}

或者

try
{
...
}
catch ( ExceptionTypeA ex )
catch ( ExceptionTypeB ex )
catch ( ExceptionTypeC ex )
{
... same code for all exceptions of A, B or C
}

我想我所说的会很好地解决异常类型。

【问题讨论】:

标签: c# exception-handling


【解决方案1】:

上述语法的问题(带有ex)是:ex 应该有哪些属性/成员?不同的异常类型不一定兼容,除非涉及继承(在这种情况下,捕获您关心的最小派生)。

目前唯一的选择是只使用Exception ex(或类似的)并在处理程序中检查(is/as)。

或者;将通用代码重构为三者都可以使用的方法?

【讨论】:

  • 这实际上是一个合理的要求,因为有时你真的想捕捉Derived1Derived2而不是Derived3,所以你不能只捕捉Base——但你想捕捉为两者做同样的事情。它在某个时候被计划用于 Java 7,其语法类似于 catch (Derived1 | Derived2 ex),并且只为您提供最接近的通用基本类型的成员,但他们已经在此版本中放弃了它。不过,一般来说,这将是对类型系统的一个有趣的补充。
  • 也许,但它伴随着成本与收益的论点。简单地为通用逻辑创建一个方法有多难?
  • 根据它在try 周围的范围内使用了多少数据,创建这种方法的工作量可以从瞬时到适度,并且生成的代码的可读性从中等复杂到一团糟。
  • 自 C#7 起,通过模式匹配在 switch 语句中提供贯穿功能。抓住Exception ex,在switch (ex) { } 语句中,你可以这样写:case ArgumentException argEx:;这种方法提供了 OP 要求的功能,并且与将复杂的错误处理移动到单独的方法中的建议兼容。见docs.microsoft.com/en-us/dotnet/csharp/pattern-matching。在 C# 8 中,您甚至可以使用 switch 表达式来更简洁;见docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-8
  • @Daniel 您应该将其添加为示例,IMO;我肯定会赞成(如果我注意到的话)
【解决方案2】:

将重复的代码包装在一个方法中。

try
{
...
}
catch ( ExceptionTypeA ex )
{
     DoSomething();
}
catch ( ExceptionTypeB ex )
{
     DoSomething();
}
catch ( ExceptionTypeC ex )
{
     DoSomething();
}
catch ( Exception ex )
{
     DoTheDefaultSomething();
}

【讨论】:

  • 这里的问题是可以从 DoTheDefaultSomething 中访问的变量范围。
  • @Nissan Fan:你是说 DoTheDefaultSomething() 应该是 DoTheDefaultSomething(ex)?
  • 不,范围为 Try ... Catch 部分的变量更多的是范围为包含 Try ... Catch 部分的函数,在这种情况下将超出范围。
【解决方案3】:

如果这是合理的,您可以从公共基类派生 TypeA、B、C。并捕获基类异常。

【讨论】:

    【解决方案4】:

    您可以捕获一般异常,然后检查类型,例如:

    catch (Exception ex)            
       {                
          if (ex is ExceptionTypeA ||
              ex is ExceptionTypeB )
               {
                   /* your code here */
               }
           else
               {
                   throw;
               }
        }
    

    编辑:根据其他答案,我希望通过提取一种方法来澄清发生了什么 - 但不是单独的捕获和通用方法,我可能会引入一种方法来澄清if 语句正在执行。所以不是

    if (ex is ExceptionTypeA || ex is ExceptionTypeB )
    

    它会变成这样:

    if (IsRecoverableByDoingWhatever(ex))
    

    我认为这比提取处理程序代码更能阐明意图(尽管这样做也可能有用)。

    【讨论】:

    • 这从来不是推荐的方法,并且该语言不是为这种方法设计的。但是,它仍然是唯一不需要复制代码的模式。您应该更新它以包括异常类型的模式匹配。这使模式变得更好。
    【解决方案5】:

    不是一个干净的方式。您可以捕获 System.Exception,然后在运行时检查类型,即。

    try
    {
    ...
    }
    catch (System.Exception ex)
    {
       if (ex is ExceptionTypeA or ExceptionTypeB or ExceptionTypeC)
       {
           ... same code ...
       }
       else
           throw;
    }
    

    ...但这很丑陋。正如 João Angelo 所说,最好为每种异常类型设置单独的 catch 块,但在每个异常类型中调用一个通用方法。

    【讨论】:

      【解决方案6】:

      简而言之,没有。我能想到两个三个备选方案:

      捕获每个异常,并调用通用方法:

      try
      {
         // throw
      }
      catch ( ExceptionTypeA ex )
      {
           HandleException();
      }
      catch ( ExceptionTypeB ex )
      {
           HandleException();
      }
      catch ( ExceptionTypeC ex )
      {
           HandleException();
      }
      
      void HandleException()
      {
      }
      

      或者捕获所有内容,并在类型上使用 if 语句:

      try
      {
         // throw
      }
      catch (Exception ex)
      {
         if (ex is ArgumentException || ex is NullReferenceException || ex is FooException)
         {
            // Handle
         }
         else
         {
            throw
         }
      }
      

      编辑: 或者,您可以这样做:

      List<Type> exceptionsToHandle = new List<Type>{ typeof(ArgumentException), typeof(NullReferenceException), typeof(FooException) };
      
      try
      {
         // throw
      }
      catch (Exception ex)
      {
         if (exceptionsToHandle.Contains(ex.GetType()))
         {
            // Handle
         }
         else
         {
            throw
         }
      }
      

      【讨论】:

        【解决方案7】:

        如果您可以访问定义自定义异常的代码,一种可能的解决方案是:

        创建自定义异常类型。

        public abstract class CustomException : Exception
        {
                //Do some stuff here
        }
        

        然后让你的所有自定义异常都派生自这个基类型:

        public class MyException1 : CustomException
        {
                // Do some stuff here
        }
        
        public class MyException2 : CustomException
        {
            // Do some stuff here
        }
        

        你已经完成了。所以现在,您需要在客户端代码中捕获自定义异常基类。

        try
        {
             //Do something that throws a custom exception
        }
        catch (CustomException ex)
        {
             // Do some shared behavior for all the custom exceptions
        }   
        

        【讨论】:

          【解决方案8】:

          如果您需要使用try 范围内的一些变量,请使用嵌套函数。即 lambda 或匿名委托:

          int x = ...;
          Action<Exception> handler = delegate(Exception ex)
          {
              // Same code for all exceptions of A, B or C.
              // You can use variable x here too.
          };    
          
          try
          {
          ...
          }
          catch (ExceptionTypeA ex) { handler(ex); }
          catch (ExceptionTypeB ex) { handler(ex); }
          catch (ExceptionTypeC ex) { handler(ex); }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2013-01-10
            • 1970-01-01
            • 1970-01-01
            • 2017-11-01
            • 2018-12-06
            • 1970-01-01
            • 1970-01-01
            • 2011-04-27
            相关资源
            最近更新 更多