thefroatgt
thefroatgt

Reputation: 916

How do I cast a list of an object to a list of an interface that the object implements in VB.net?

I am working in VB.net and have a Class, Foo, that implements an interface, IBar. I have a List of Foo's, but I need to pass a list of IBar's into a function, but I keep getting casting errors, even when I use DirectCast. My code is

Class Foo
    Implements IBar
End Class

Interface IBar
End Interface

Sub DoIt(ByVal l As List(Of IBar))
End Sub

Sub Main()
    Dim FooList As New List(Of Foo)
    DoIt(FooList)
End Sub

Sub Main2()
    Dim FooList As New List(Of Foo)
    DoIt(DirectCast(FooList, List(Of IBar)))
End Sub

Sub MainWorks()
    Dim FooList As New List(Of Foo)
    Dim IBarList As New List(Of IBar)

    For Each f As Foo In FooList
        IBarList.Add(f)
    Next

    DoIt(DirectCast(IBarList, List(Of IBar)))
    DoIt(IBarList)
End Sub

In both Main and Main2 I get

Value of type 'System.Collections.Generic.List(Of FreezePod.Pod.Foo)' cannot be converted to 'System.Collections.Generic.List(Of FreezePod.Pod.IBar)'.

MainWorks works, but it would be really annoying and inefficient to have to do that everywhere I want to call this function.

Upvotes: 6

Views: 7407

Answers (4)

Colin Burnett
Colin Burnett

Reputation: 11518

Duplicate question but for C# (same problem). There are various answers there you can translate to VB. The reason why you can't is covariance and contravariance.

I'm not a VB guy but my preferred C# way is to call System.Collections.Generic.List<T>.ConvertAll<Tout>(x => (Tout)x). (I don't know how that translates, if it does, to VB.)

VB translation:

System.Collections.Generic.List(Of T).ConvertAll(Of TOut)(Function(x) CType(x, TOut))

Upvotes: 4

AnotherDan
AnotherDan

Reputation: 396

Is a derived Base Class not an option, and have the Base Class implement the interface. That would make it work.

Class BaseFoo
    Implements IBar
End Class

Class Foo
    Inherits BaseFoo
End Class

Sub DoIt(ByVal l As List(Of BaseFoo))
End Sub

Something like it.

Upvotes: 1

AnotherDan
AnotherDan

Reputation: 396

Adding this solution as another answer, this should do what you want.

Sub DoIt(Of T As IBar)(ByVal l As List(Of T))
End Sub

Defining the sub using generics.

Upvotes: 2

panopticoncentral
panopticoncentral

Reputation: 1793

The problem is that generic types like List(Of T) don't convert to some other List(Of U) even if the cast is guaranteed to be safe. Help is coming for this in VS2010, which doesn't really help you now, of course.

As I think was also suggested in the thread linked to, if DoIt can take an IEnumerable of IBar instead of a list, you could do:

DoIt(FooList.Cast(Of IBar))

or if you really needed a list (and could take the overhead), you could get a list:

DoIt(FooList.Cast(Of IBar).ToList)

Upvotes: 5

Related Questions