Scenario:
I have a loop that iterates over an Array
of COM objects and does some work using them.
My fear, working with COM objects, is that some exception will creep up (possibly on another user's environment) and cause the loop to break mid-way through processing these objects.
So, let's say (hypothetically) an exception occurs on file 32 of 173.
I see three options:
-
Show the exception, inform the user that only 32 files were
processed, and we then have to manually do the work on the remaining 141 files. -
Undo all the work done on the first 32 files, inform the user the
request couldn't be completed and show the exception. This is less
than ideal because by the time we are at this procedure, a lot of
up-front work has been done (creating files, incrementing serial
numbers, etc.) which would be cumbersome and difficult to undo. In the end, we end up with all 172 files needing manual work. -
Catch the exception, store it in a List, continue to try to
process the rest of the files, then after trying to process all files, inform the user of any exceptions that occurred and any files which couldn't be processed. Best case we only have one file to manually do work on, and worst
case we are left with 141 files – same as the first option.
Event horizon:
I'm new to programming. In fact I just wrote (am writing) my first add-in which I posted up on SE::Code Review.
Now, I'm of the mindset that option three makes the most sense – let's at least give hope a chance and see what happens with the rest of them, no?
So here's my implementation (well simplified, but this is the pattern):
Sub Main()
Dim Exceptions as New List(of Exception)
Try
TryThatFunkyCOMthing (Exceptions)
If Exceptions.Count>0 Then
For Each ex As Exception in Exceptions
MessageBox.Show(ex.ToString)
Next
End If
Catch ex As Exception
MessageBox.Show(ex.ToString)
End Try
End Sub
Private Sub TryThatFunkyCOMthing (ByRef ExceptionBuffer as List(of Exception))
For each COMthingy in COMthings
Try
COMthingy.DoSomething
Catch ex As SpecificException
COMthingy.WeAreBlewedUp
Catch ex As Exception
ExceptionBuffer.Add(ex)
End Try
Next
End Sub
One of the reviewers on CR gave me some feedback saying I should NOT be doing this. He said I should want the loop to stop if an exception occurs.
He linked to this SO Q&A regarding handling general exceptions, which I read (a few times now) and I think this solution falls under "failing gracefully". As mentioned above, I'm not trying to swallow exceptions, just control how/when they are handled so that my program behaves in a manner I can predict and depend on, even in the event of a catastrophic or unexpected exception.
What I'd like to know:
- If this is bad practice, why?
- Out of the three options I provided, which would you choose? – OR – Is there a mysterious and much better fourth option I'm missing?
Best Answer
I understand why you want to do this. The way you are doing it is not what I would do.
Rather than collect a list of exception objects, I would process those objects as they happen. By collecting a list to process later you run the risk of losing them before they get processed. At that point, without intending to do so, your program has swallowed the exceptions. The user will know nothing bad has happened. When they find out, the hard way, their experience with your program will be a poor one.
Whatever you want to do with the exceptions, do it as soon as they happen. Continue the loop if you like but process/log those exceptions regardless.