C#异常处理失败

C#异常处理失败,c#,exception-handling,C#,Exception Handling,可能重复: 在C#中是否有任何方法可以轻松实现以下PSEDOO代码: try { ... } catch ( ExceptionTypeA, ExceptionTypeB, ExceptionTypeC as ex) { ... same code for all threw } 或 我想我要说的是,在异常类型上会失败。前面提到的语法(使用ex)的问题是:ex应该有哪些属性/成员?不同的异常类型不一定是兼容的,除非涉及到继承(在这种情况下,捕获您关心的最不派生的异常类型) 当前唯一的选项是只

可能重复:

在C#中是否有任何方法可以轻松实现以下PSEDOO代码:

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


我想我要说的是,在异常类型上会失败。

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

当前唯一的选项是只使用
Exception ex
(或类似选项)并在处理程序内检查(
is
/
as


或;将公共代码重构成一个三者都可以使用的方法

将重复代码包装到方法中

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

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

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

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))
我认为这比提取处理程序代码更能阐明目的(尽管这样做可能也很有用)。

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

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

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

简言之,不。我可以想出两种或三种备选方法:

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

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
   }
}
List exceptionsToHandle=新列表{typeof(ArgumentException)、typeof(NullReferenceException)、typeof(footeexception)};
尝试
{
//扔
}
捕获(例外情况除外)
{
if(exceptionsToHandle.Contains(例如GetType()))
{
//处理
}
其他的
{
扔
}
}

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

创建自定义异常类型

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
}   

如果需要使用
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); }
intx=。。。;
操作处理程序=委托(异常示例)
{
//A、B或C的所有例外情况的代码相同。
//这里也可以使用变量x。
};    
尝试
{
...
}
catch(ExceptionTypeA-ex){handler(ex);}
catch(ExceptionTypeB-ex){handler(ex);}
catch(ExceptionTypeC-ex){handler(ex);}

将通用代码提取到函数中不是一个选项?另请参见此处的解决方案:C#6方式:这里的问题是可以从DoTheDefaultSomething中访问变量的范围。@Nissan Fan:您是否建议DoTheDefaultSomething()应为DoTheDefaultSomething(ex)?不,更多的变量范围为Try。。。Catch部分的作用域是包含Try。。。在这种情况下,Catch部分将超出范围。这实际上是一个合理的请求,因为有时您确实希望捕获
Derived1
Derived2
,但不希望捕获
Derived3
,因此您不能只捕获
Base
,但您希望对这两个部分都做同样的事情。它在某种程度上是为Java7设计的,语法类似于
catch(Derived1 | derived2ex)
,只为您提供最接近的公共基类型的成员,但他们在本版本中放弃了它。尽管如此,这将是对类型系统的一个有趣的补充。也许,但它与成本与效益的争论是一致的。简单地为公共逻辑创建一个方法有多难?根据它使用的范围
try
中的数据量,创建这样一个方法的努力可以是瞬间的,也可以是现代的,从C#7开始,通过模式匹配在
switch
语句中提供了下拉功能。Catch
Exception ex
,并且在
switch(ex){}
语句中,您可以这样做:
case ArgumentException argEx:
;这种方法提供了OP请求的功能,并且与将详细的错误处理转移到单独方法的建议兼容。看见在C#8中,您甚至可以使用开关表达式来更简洁;看。@Daniel你应该加上这个作为例子的答案,IMO;我肯定会支持它(如果我注意到的话),这从来不是推荐的方法,而且语言也不是为这种方法设计的。然而,它仍然是唯一不需要重复代码的模式。您应该更新它以包括异常类型上的模式匹配。这使得模式变得更好。
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); }