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

you*_*hut 3 .net vb.net collections interface

我有一个实现IWeightable的Entity类:

Public Interface IWeightable

    Property WeightState As WeightState

End Interface
Run Code Online (Sandbox Code Playgroud)

我有一个WeightCalculator类:

Public Class WeightsCalculator

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

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

End Class
Run Code Online (Sandbox Code Playgroud)

遵循这个过程:

  1. 实例化实体集合 Dim entites As New List(Of Entity)
  2. 实例化WeightsCalculator Dim wc As New WeightsCalculator(...)

为什么我不能做wc.Calculate(实体)?我收到:

无法转换类型为'System.Collections.Generic.List 1[mynameSpace.Entity]' to type 'System.Collections.Generic.IList1 [myNamespace.IWeightable]'的对象.

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

Kon*_*lph 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())
Run Code Online (Sandbox Code Playgroud)

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

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

Public Sub Calculate(Of T As IWeightable)(ByVal entites As IList(Of T))
    ...
End Sub
Run Code Online (Sandbox Code Playgroud)


Jon*_*eet 6

A List(Of Entity)不是IList(Of IWeightable).考虑这段代码(其中的OtherWeightable实现IWeightable):

Dim list As IList(Of IWeightable) = New List(Of Entity)
list.Add(new OtherWeightable)
Run Code Online (Sandbox Code Playgroud)

编译的第二行 - 没有什么可疑的 - 但你不想要一个OtherWeightable元素List(Of Entity).

.NET 4 以泛型方差的形式对此进行了部分解决.如果您的方法只迭代,您可以将签名更改为:Calculateentities

Public Sub Calculate(ByVal entites As IEnumerable(Of IWeightable))
Run Code Online (Sandbox Code Playgroud)

虽然IList(Of T)不变的,IEnumerable(Of T)协变T,因为API永远只允许类型的值T返回由它-没有任何类型的参数T中的方法IEnumerable(Of T).所以有转换List(Entity)IEnumerable(Of IWeightable).

通用方差是一个毛茸茸的话题 - 在NDC 2010上我给出了一个你可能觉得有用的演示文稿.您可以在NDC 2010视频页面上观看.(搜索"差异.")

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