Reputation: 948
I have an Entity class which Implements IWeightable:
Public Interface IWeightable
Property WeightState As WeightState
End Interface
I have a WeightCalculator class:
Public Class WeightsCalculator
Public Sub New(...)
...
End Sub
Public Sub Calculate(ByVal entites As IList(Of IWeightable))
...
End Sub
End Class
Following the process:
Dim entites As New List(Of Entity)
Dim
wc As New WeightsCalculator(...)
Why can I not do wc.Calculate(entities)? I receive:
Unable to cast object of type 'System.Collections.Generic.List
1[mynameSpace.Entity]' to type 'System.Collections.Generic.IList
1[myNamespace.IWeightable]'.
If Entity implements IWeightable why is this not possible?
Upvotes: 3
Views: 222
Reputation: 1501113
A List(Of Entity)
isn't an IList(Of IWeightable)
. Consider this code (where OtherWeightable
implements IWeightable
):
Dim list As IList(Of IWeightable) = New List(Of Entity)
list.Add(new OtherWeightable)
The second line as to compile - there's nothing suspicious about it - but you don't want an OtherWeightable
element in a List(Of Entity)
.
.NET 4 has a partial solution to this in the form of generic variance. If your Calculate
method only iterates over entities
, you could change the signature to this:
Public Sub Calculate(ByVal entites As IEnumerable(Of IWeightable))
Although IList(Of T)
is invariant, IEnumerable(Of T)
is covariant in T
, because the API only ever allows values of type T
to be returned by it - there are no parameters of type T
in methods of IEnumerable(Of T)
. So there's a conversion from List(Entity)
to IEnumerable(Of IWeightable)
.
Generic variance is a hairy topic - at NDC 2010 I gave a presentation on it which you may find useful. You can watch it at the NDC 2010 videos page. (Search for "variance.")
If you're using .NET 3.5 or earlier, Konrad's suggestion of making Calculate
generic is a fine choice.
Upvotes: 6
Reputation: 545668
This doesn’t work.
Assume you have a different class, OtherEntity
, that would also implement the interface. If your above code would work, the method Calculate
could add an instance of OtherEntity
to your list of Entity
:
Dim entities As New List(Of Entity)()
Dim weightables As List(Of IWeightable) = entities ' VB forbids this assignment!
weightables.Add(New OtherEntity())
That is illegal. If it weren’t, what would the content of entities(0)
be?
To make the code work, use a generic method with a constraint instead:
Public Sub Calculate(Of T As IWeightable)(ByVal entites As IList(Of T))
...
End Sub
Upvotes: 6