混乱 - 实施的界面需要铸造?

时间:2011-01-12 13:28:16

标签: .net vb.net collections interface

我有一个实现IWeightable的实体类:

Public Interface IWeightable

    Property WeightState As WeightState

End Interface

我有一个WeightCalculator类:

Public Class WeightsCalculator

    Public Sub New(...)
        ...
    End Sub

    Public Sub Calculate(ByVal entites As IList(Of IWeightable))
        ...
    End Sub

End Class

遵循这个过程:

  1. 实例化实体集合 Dim entites As New List(Of Entity)
  2. 实例化WeightsCalculator Dim wc As New WeightsCalculator(...)
  3. 为什么我不能做wc.Calculate(实体)?我收到了:

      

    无法投射类型的对象   'System.Collections.Generic.List 1[mynameSpace.Entity]' to type 'System.Collections.Generic.IList 1 [myNamespace.IWeightable]'。

    如果Entity实现IWeightable,为什么这不可能?

2 个答案:

答案 0 :(得分:6)

这不起作用。

假设您有一个不同的类OtherEntity,它也会实现该接口。如果您的上述代码有效,则方法Calculate可以将OtherEntity的实例添加到您的Entity列表中:

Dim entities As New List(Of Entity)()
Dim weightables As List(Of IWeightable) = entities ' VB forbids this assignment!
weightables.Add(New OtherEntity())

这是非法的。如果不是,那么entities(0)的内容会是什么?

要使代码有效,请使用带约束的泛型方法:

Public Sub Calculate(Of T As IWeightable)(ByVal entites As IList(Of T))
    ...
End Sub

答案 1 :(得分:6)

List(Of Entity)不是IList(Of IWeightable)。请考虑此代码(其中OtherWeightable实现IWeightable):

Dim list As IList(Of IWeightable) = New List(Of Entity)
list.Add(new OtherWeightable)

关于编译的第二行 - 没有任何可疑之处 - 但你不想在OtherWeightable中使用List(Of Entity)元素。

.NET 4以 generic variance 的形式提供了部分解决方案。如果您的Calculate方法仅迭代entities,则可以将签名更改为:

Public Sub Calculate(ByVal entites As IEnumerable(Of IWeightable))

虽然IList(Of T) 不变,但IEnumerable(Of T)中的T协变,因为API只允许使用T类型的值{1}}由返回 - T的方法中没有IEnumerable(Of T)类型的参数。因此,从List(Entity)转换为IEnumerable(Of IWeightable)

通用差异是一个毛茸茸的话题 - 在NDC 2010上我做了一个你可能觉得有用的演示文稿。您可以在NDC 2010 videos page处观看。 (搜索“方差”。)

如果您使用的是.NET 3.5或更早版本,Konrad建议Calculate通用是一个不错的选择。