Question List to IList Polymorphism Attempt results in InvalidCastException?

chess123mate

Member
Joined
Jan 29, 2010
Messages
5
Location
Canada
Programming Experience
5-10
In a program I am writing (in VB.NET, 2008), I have 2 classes, "Receipt" and "Group", each with similar properties, both implementing a custom interface entitled "IIDUser".
In my program, I have a number of lists of "Receipt" and "Group", declared like:
Friend receipts as List(Of Receipt)

I have written a few functions that apply equally to managing both lists of receipts and groups, declared like this one:
Friend Function getNextAvailableUserLabel(ByRef theList As IList(Of IIDUser), ByVal startLabel As Short) As Short

Then called like this:
getNextAvailableUserLabel(receipts, s)

I did all this in an attempt for interface-based polymorphism, as I thought writing 2 identical functions (except for that one would be for lists of receipts while the other for lists of groups) would be bad practice (and waste time).

However, I get an "InvalidCastException" during runtime. It is explained, "Unable to cast object of type 'System.Collections.Generic.List`1[Receipt_Sorter_v2.Receipt]' to type 'System.Collections.Generic.IList`1[Receipt_Sorter_v2.IIDUser]'."

If I declare the function to just be a "List(Of IIDUser)", it complains "Value of type 'System.Collections.Generic.List(Of Receipt_Sorter_v2.Receipt)' cannot be converted to 'System.Collections.Generic.List(Of Receipt_Sorter_v2.IIDUser)'." in the error list.

Can anyone tell please me what I'm doing wrong and how to fix this?
Thanks,
chess123mate
 
The problem is that when you specify the type parameter you create a specific type, for example List(A) is one List type and List(B) is another List type.

The purpose of your Function Method(ByRef theList) is not explained, so different solutions may exist. First off it seems strange that you declare the parameter ByRef, does that function really need to dereference the callers list? Does the function also need to change the items in the list? Secondly, does the parameter value need to be in List form, or could an array do? And what about the caller, does it need to keep the List as specific type, or would a List(Of IId) do? Three options below provide alternate solutions depending on the answer to these questions.

type definitions
VB.NET:
Interface IId
Class Foo : Implements IId
option A
VB.NET:
Sub Method(ByVal items As List(Of IId))
-------
Dim l As New List(Of Foo)
Method(New List(Of IId)(l.ToArray))
option B
VB.NET:
Sub Method(ByVal items As List(Of IId))
-------
Dim l As New List(Of IId)
l.Add(New Foo)
Method(l)
option C
VB.NET:
Sub Method(ByVal items() As IId)
-------
Dim l As New List(Of Foo)
Method(l.ToArray)
 
Thanks for the explanation, although, as I said, the code I linked to fixed the problem (similar to what you're suggesting).
I am currently using "Function getNextAvailableUserLabel(Of TempClass As IIDUser)(ByRef theList As List(Of TempClass), etc)". I do not know if this is less efficient that just declaring "TempClass" once elsewhere (though I'd rename it if so).

I am using ByRef for performance, although I recently learned through trial and error that it seems meaningless to use ByRef rather than ByVal, as List - being an object - is not duplicated, right?
 
The object is not duplicated, true, but the reference (integer address) is. You'd be at the limit of using VB.Net language in the first place if that mattered.

Using generics is also a perfectly valid solution, I was just sketching out some alternative solutions to handle these types of objects.
 
Back
Top