无法将子类型列表传递给接口类型列表(由子类型实现)到 Visual Basic 中的函数 + 也无法转换

Cannot pass List of subtype to a List of interface type (implemented by subtype) to a function in Visual Basic + Cannot be casted either

我只需要使用 1 个函数来处理包含接口类型的列表,以便我可以为每个子类型重用它,但在处理函数调用堆栈上层的列表项时,我还需要知道具体类型:

LoadAItems 调用 GetA,后者调用 FilterItems

FilterItems 需要通用以便 GetB 也可以调用和使用它。

问题是尝试将子类型列表传递给通用 FilterItems 方法是不允许的:

"Cannot convert type 'List(Of AListItem)' to parameter type 'List(Of IListItem)'"

我尝试将列表中的每个 AListItem 对象转换为 IListItem 并将其添加到新列表,但问题是 FilterItems 函数应该从列表中删除元素。如果我从新列表中删除元素,那么它不会影响旧列表。我可以将它转换回来,但是为了能够使用该功能这很麻烦。

我不能将所有内容都更改为 List(Of IListItem),因为那样我就需要始终从 FilterItemsGetA / GetB 中转换返回值,因为 LoadAItems / LoadBItems 需要知道具体类型。

我明白为什么向下转换不好,但为什么我不能向上转换为具体类型正在实现的接口类型?

我已经试过了:

FilterItems(CType(items, List(Of IListItem))

但这是不允许的:

"Value of type 'List(Of AListItem)' cannot be converted to 'List(Of IListItem)'"

这是我的代码示例:

Public Class AListItem
    Implements IListItem

    'Properties here

End Class

Public Class BListItem
    Implements IListItem

    'Properties here

End Class

Private Sub FilterItems(items As List(Of IListItem))
    'Remove items from the list that meet some condition
    items.RemoveAll(Function(item) ...)     

    'Does not matter what the items class type is
End Sub

Public Function GetA() As List(Of AListItem)
    Dim items As List(Of AListItem)

    items = CallDatabase()

    FilterItems(items) ' Does not allow!

    Return items
End Function

Public Function GetB() As List(Of BListItem)
    Dim items As List(Of BListItem)

    items = CallDatabase()

    FilterItems(items) ' Does not allow!

    Return items

End Function

Public Sub LoadAItems()
    Dim items As List(Of AListItem)

    items = GetA()

    'Do specific AListItem stuff (cannot use interface!)
End Sub

Public Sub LoadBItems()
    Dim items As List(Of BListItem)

    items = GetB()

    'Do specific BListItem stuff (cannot use interface!)
End Sub

与其拥有接受和操作 List(Of IListItem) 的函数,不如创建一个签名为:

的函数
Private Boolean IsGoodItem(IListItem)

希望可以直接转换 FilterItems 中的现有代码以适应那里。然后只需更改:

Public Function GetA() As List(Of AListItem)
    Dim items As List(Of AListItem)

    items = CallDatabase()

    FilterItems(items) ' Does not allow!

    Return items
End Function

Public Function GetA() As List(Of AListItem)
    Dim items As List(Of AListItem)

    items = CallDatabase()

    Return items.Where(IsGoodItem).ToList()
End Function

而且您仍然可以(相当一部分)代码重用,而不会遇到 covariance/contravariance 问题。 (我认为编译器会很乐意为 Where 推断类型,或者您可能必须在此处插入显式类型注释)

如果我正确地理解了你想要做什么,你应该能够使函数本身通用:

Private Sub FilterItems(Of T As IListItem)(items As List(Of T))

Of T As IListItem 添加了 T 必须的约束,或者继承自 IListItem.

然后你可以这样称呼它:

Public Function GetA() As List(Of AListItem)
    Dim items As List(Of AListItem)

    items = CallDatabase()

    FilterItems(Of AListItem)(items)

    Return items
End Function

Public Function GetB() As List(Of BListItem)
    Dim items As List(Of BListItem)

    items = CallDatabase()

    FilterItems(Of BListItem)(items)

    Return items
End Function