我有一个实现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
遵循这个过程:
Dim entites As New List(Of Entity)
Dim
wc As New WeightsCalculator(...)
为什么我不能做wc.Calculate(实体)?我收到了:
无法投射类型的对象 'System.Collections.Generic.List
1[mynameSpace.Entity]' to type 'System.Collections.Generic.IList
1 [myNamespace.IWeightable]'。
如果Entity实现IWeightable,为什么这不可能?
答案 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
通用是一个不错的选择。