简体   繁体   中英

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.

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)

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))

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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM