18

Possible Duplicate:
Catch multiple Exceptions at once?

Is there any way in C# to easily achieve the following pseduo-code:

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

Or

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

I guess what I'm saying would be great would be fall-through on exception types.

Community
  • 1
  • 1
Keith Adler
  • 20,880
  • 28
  • 119
  • 189

8 Answers8

19

The problem with the syntax as mentioned (with an ex) is: what properties/members should ex have? Different exception types are not necessarily compatible, unless there is inheritance involved (in which case, catch the least-derived that you care about).

The only current option is to just use Exception ex (or similar) and check (is/as) inside the handler.

Or; refactor the common code into a method that can be used by all three?

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • 1
    It's actually a reasonable request, because sometimes you really want to catch `Derived1` and `Derived2` but not `Derived3`, so you can't just catch `Base` - and yet you want to do the same thing for both. It was slated for Java 7 at some point, with syntax like `catch (Derived1 | Derived2 ex)`, and only giving you members of the closest common base type, but they've since dropped it for this release. Still, would be an interesting addition to the type system in general. – Pavel Minaev Nov 18 '09 at 22:18
  • Perhaps, but it goes along with cost VS benefit argument. How hard is it to simply create a method for the common logic? – Ed S. Nov 18 '09 at 22:19
  • 2
    Depending on how much data it uses from the scope surrounding `try`, the effort of creating such a method can be anywhere from momentary to moderade, and readability of the resulting code anything from moderately complex to a complete mess. – Pavel Minaev Nov 18 '09 at 23:17
  • 3
    Fall-through functionality is available as of C#7 in the `switch` statement through pattern matching. Catch `Exception ex`, and in a `switch (ex) { }` statement, you can make cases like this: `case ArgumentException argEx:`; this approach offers the functionality OP requested and is compatible with the suggestion to move elaborate error handling into a separate method. See https://learn.microsoft.com/en-us/dotnet/csharp/pattern-matching. In C# 8, you can even use switch expressions for more terseness; see https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-8. – Daniel Oct 03 '19 at 17:09
  • 1
    @Daniel you should add that as an answer with example, IMO; I'd definitely upvote it (if I notice it) – Marc Gravell Oct 03 '19 at 20:10
  • @MarcGravell I wanted to, but I'm not able to add new answers--maybe because it's marked as a duplicate? – Daniel Oct 04 '19 at 19:01
11

In short, no. I can think of two three alternatives:

Catch each exception, and call a common method:

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

void HandleException()
{
}

Or catch everything, and use an if statement on the type:

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

EDIT: OR, you could do something like this:

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
   }
}
Philip Wallace
  • 7,905
  • 3
  • 28
  • 40
6

You can catch a general exception and then examine the type, e.g.:

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

Edit: in line with other answers I'd be looking to clarify what's going on by pulling out a method - but rather than individual catches and a common method, I'd probably introduce a method to clarify what the contents of the if statement is doing. So instead of

if (ex is ExceptionTypeA || ex is ExceptionTypeB )

it'd become something like:

if (IsRecoverableByDoingWhatever(ex))

which I think would clarify the intent more than pulling out the handler code (although that might be useful to do too).

FinnNk
  • 3,249
  • 23
  • 25
  • This has never been the recommended approach, and the language wasn't designed for this approach. However, it's still the only pattern that doesn't require duplicating code. You should update this to include pattern matching on exception types. That makes the pattern even better. – Christian Findlay May 12 '19 at 23:41
4

Wrap the repetitive code in a method.

try
{
...
}
catch ( ExceptionTypeA ex )
{
     DoSomething();
}
catch ( ExceptionTypeB ex )
{
     DoSomething();
}
catch ( ExceptionTypeC ex )
{
     DoSomething();
}
catch ( Exception ex )
{
     DoTheDefaultSomething();
}
Clark
  • 1,006
  • 8
  • 14
  • 1
    The problem here is scope of variables being accessible from within DoTheDefaultSomething. – Keith Adler Nov 18 '09 at 22:14
  • @Nissan Fan: Are you suggesting that DoTheDefaultSomething() should be DoTheDefaultSomething(ex)? – Clark Nov 19 '09 at 14:40
  • No, more that variables scoped to the Try ... Catch portion are that are scoped to the function that contains the Try ... Catch portion would be out of scope in this scenario. – Keith Adler Nov 19 '09 at 16:18
3

If you need to use some variables from the scope of try, use a nested function. That is, a lambda or an anonymous delegate:

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); }
Pavel Minaev
  • 99,783
  • 25
  • 219
  • 289
2

If you have access to the code that define the custom exceptions, one possible solution is:

Create a custom exception type.

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

Then make all your custom exceptions derive from this base type:

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

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

You are done. So now, all you need in your client code is to catch the custom exception base class.

try
{
     //Do something that throws a custom exception
}
catch (CustomException ex)
{
     // Do some shared behavior for all the custom exceptions
}   
Pedro
  • 2,300
  • 1
  • 18
  • 22
1

You would derive TypeA, B, C from a common base class if this is reasonable. And catch the base class exception.

Alex
  • 1,997
  • 1
  • 16
  • 31
1

Not a clean way. You could just catch System.Exception and then check the type at runtime, ie.

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

... but this is pretty ugly. It would be nicer to, as João Angelo said, have separate catch blocks for each exception type, but call a common method in each of them.

EMP
  • 59,148
  • 53
  • 164
  • 220