views:

53

answers:

4

I am doing little hobby project in C#, a language I do not know well, and have stumbled upon the following:

Suppose you have an asynchronous operation implemented by using BackgroundWorker. Now if there is an exception, event RunWorkerCompleted will be raised and RunWorkerCompletedEventArgs.Error will be non-null.

Is the following the canonical way then to handle different exception types? (Here all the exception kinds are siblings WRT inheritance)

if (e.Error != null)
{
    FirstKindOfException e1 = e as OneKindOfException;
    SecondKindOfException e2 = e as SecondKindOfException;
    ...
    LastKindOfException en = e as LastKindOfException;
    if (e1 != null)
    {
        ...
    }
    else if (e2 != null)
    {
        ...
    }
    ...
    else
    {
        ...
    }
}

It works, but... it doesn't feel right.

+2  A: 

Using is operator maybe?

if (e is OneKindOfException)
{
}
else if (e is SecondKindOfException)
{
}
Philippe
+4  A: 

Use the is operator:

if (e.Error is FirstKindOfException) {
   //...
}
else if (e.Error is SecondKindOfException) {
   //...
}
//etc..

Or just cut it short since you don't know how to handle these exceptions anyway. If you did then you would have caught them in the DoWork() event handler, there's no point in trying to handle them after the state has evaporated:

if (e.Error != null) throw new BackgroundTaskFailedException(e.Error);
Hans Passant
Rethrowing is bad! Performance suffers with it...
Aliostad
@Aliostad: the point is to not catch exceptions that you don't know how to handle. Perf really doesn't matter, the program will crash a few milliseconds slower. If the exception is recoverable then it should have been taken care of in DoWork().
Hans Passant
@Hans well he wants to handle it and prevent the crash and that is why he is checking it. I would agree that he has to handle in the client and not in the BackgroundWorker itself but in the end, as I said, usually no point in differentiating it.
Aliostad
By the way, congrat on hitting 100K!
Aliostad
+1  A: 

Yes, you can do this but really depends what you are going to do with all those exception types. Normally this will only be shown to the user so there is no need to check the type of the error.

Also you need to keep in mind that it is likely the type of the exception could be AggregateException - which is return from the Task<T> operations - so you need to be carefull.

Aliostad
Never heard of AggregateException. Should I be concerned if I only use BackgroundWorker and not Task<T>?
Laurynas Biveinis
If you use Task<T> then you always get back AggregateException (which will contain rest of the exceptions). I am not sure about BackgroundWorker but that could be the same. But if you have not received it, then it is fine and not to worry about it.
Aliostad
+4  A: 

You could use is to keep each test tightly scoped:

if (e.Error is FirstKindOfException )
{
    ...
}
else if (e.Error is SecondKindOfException)
{
    ...
}

(then re-cast if you want special values from the exception)

To be honest, though, it is pretty rare that I need to handle lots of different types of exceptions. In most cases, it is fine to simply recover (compensate) to a known state and report the error appropriately. Generally I prefer to test for likely errors before I start the action, so an exception truly is something exceptional.

Marc Gravell
Right, but in the code e1 and e2 should both be e.Error. Rollback if you disagree.
Henk Holterman
@Henk actully I intended just "e" but you are right - it was incorrect as written.
Marc Gravell