Tuesday, June 9, 2009

Arraylist and generics don't mix with IEnumerable(Of T).GetEnumerator.

The other day I was writing an in-house tool to assist in some upgrades we were performing on client installations. This tool was supposed to perform its operations on a batch of items, and display the results upon completion.

Since processing this batch of items was a lengthy endeavor, I wanted the failure to process one of the items to simply be recorded and allow the processing of the others to continue. Part of the processing of each item was a call to multiple web services, so I would need a way to handle the collection of errors along the way and make them available for their eventual display.

I had what I thought was a clever idea: a private Arraylist of exceptions that occurred during processing.

Public Class BatchExceptions
Implements ICollection(Of System.Exception)

Private mExceptionlist As ArrayList
.
.
.
End Class

That way, I could simply iterate over the list and perform the standard exception handling, like so:

Dim exc As Exception
For Each exc In BatchExceptions
HandleError(exc)
Next

Of course, in order to make use of the "For Each" construct, I had to implement the GetEnumerator of the ICollection interface.

Public Function GetEnumerator() As System.Collections.Generic.IEnumerator(Of System.Exception) _
Implements System.Collections.Generic.IEnumerable(Of System.Exception).GetEnumerator
Return (mExceptionlist.GetEnumerator)
End Function

Cool. Only one problem:




That was OK though, because I was using generics after all. The compiler was being helpful and reminding me that I had to specify 'IEnumerator(Of Exception)':




Public Function GetEnumerator() As System.Collections.Generic.IEnumerator(Of System.Exception) _
Implements System.Collections.Generic.IEnumerable(Of System.Exception).GetEnumerator
Return (DirectCast(mExceptionlist.GetEnumerator, IEnumerator(Of Exception)))
End Function

Everything compiled fine, but at run-time I got the following RTE:

Unable to cast object of type 'ArrayListEnumeratorSimple' to type 'System.Collections.Generic.IEnumerator`1[System.Exception]'.




This was frustrating. It seemed like the compiler failed to warn me of this incompatibility, and simply kicked the can on down the road to the run-time to deal with.

Solution:


Well, I did a little poking around and finally ended up replacing my Arraylist with a list like so:

private mExceptionlist as System.Collections.Generic.list

Well, that did the trick but I can't say it was as intuitive as it would seem. It makes sense, in hindsight, but why did I have to get some cryptic RTE? Why couldn't the compiler have picked up on my use of an ArrayList and say, "Hey dummy - use a generic list!"? Still, I have a new trick to toss in my bag for the time I want to implement an enumerator on an Arraylist!

No comments:

Post a Comment