views:

448

answers:

8

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.

+11  A: 

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
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
Perhaps, but it goes along with cost VS benefit argument. How hard is it to simply create a method for the common logic?
Ed Swangren
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
+4  A: 

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

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

Alex
+4  A: 

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
+1  A: 

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.

Evgeny
+4  A: 

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
+1  A: 

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
+1  A: 

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