19

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.

3

8 Answers 8

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?

Sign up to request clarification or add additional context in comments.

6 Comments

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.
Perhaps, but it goes along with cost VS benefit argument. How hard is it to simply create a method for the common logic?
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.
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 learn.microsoft.com/en-us/dotnet/csharp/pattern-matching. In C# 8, you can even use switch expressions for more terseness; see learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-8.
@Daniel you should add that as an answer with example, IMO; I'd definitely upvote it (if I notice it)
|
10

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
   }
}

Comments

5

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).

1 Comment

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.
3

Wrap the repetitive code in a method.

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

3 Comments

The problem here is scope of variables being accessible from within DoTheDefaultSomething.
@Nissan Fan: Are you suggesting that DoTheDefaultSomething() should be DoTheDefaultSomething(ex)?
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.
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); }

Comments

1

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

Comments

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.

Comments

1

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
}   

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.