2011-01-12 7 views
3

Ich habe eine Klasse Entity, die IWeightable Implementiert:Verwirrung - implementiertes Interface benötigt Casting?

Public Interface IWeightable 

    Property WeightState As WeightState 

End Interface 

ich eine Gewichtsberechnungen Klasse:

Public Class WeightsCalculator 

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

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

End Class 

Prozess Folgende:

  1. Instantiate Sammlung von Entity Dim entites As New List(Of Entity)
  2. Instantiate WeightsCalculator Dim wc As New WeightsCalculator(...)

Warum kann ich wc.Calculate (Entitäten) nicht tun? Ich erhalte:

Kann Objekt vom Typ werfen 'System.Collections.Generic.List 1[mynameSpace.Entity]' to type 'System.Collections.Generic.IList 1 [myNamespace.IWeightable]'.

Wenn Entity implementiert EWeigbar warum ist das nicht möglich?

Antwort

6

Dies funktioniert nicht.

Angenommen, Sie haben eine andere Klasse, OtherEntity, die auch die Schnittstelle implementieren würde. Wenn Ihr würde obigen Code arbeiten, wobei das Verfahren Calculate könnte eine Instanz von OtherEntity in die Liste der Entity hinzufügen:

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

Das ist illegal. Wenn nicht, was wäre der Inhalt von entities(0)?

Um den Code Arbeit zu machen, verwenden Sie eine generische Methode mit einer Einschränkung statt:

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

Ah, ich wusste, dass ich naiv war. Ich werde die generische Methode implementieren. – youwhut

6

A List(Of Entity) kein IList(Of IWeightable) ist. Betrachten Sie diesen Code (wo OtherWeightable implementiert IWeightable):

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

Die zweite Zeile zu kompilieren - es gibt nichts Verdächtiges über sie - aber sie will nicht, dass ein OtherWeightable Element in einem List(Of Entity).

. NET 4 hat eine teilweise Lösung zu diesem in Form von generische Varianz. Wenn Ihr Calculate Methode nur iteriert über entities, könnten Sie die Signatur dies ändern:

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

Obwohl IList(Of T)invariant ist, IEnumerable(Of T) ist covariant in T, da die API immer nur Werte vom Typ erlaubt T zu be zurückgegeben von ihm - es gibt keine Parameter des Typs T in Methoden von IEnumerable(Of T). Es gibt also eine Konvertierung von List(Entity) zu IEnumerable(Of IWeightable).

Generische Varianz ist ein haariges Thema - bei NDC 2010 habe ich eine Präsentation darüber gehalten, die Sie nützlich finden können. Sie können es unter der NDC 2010 videos page ansehen. (Suche nach "varianz.")

Wenn Sie .NET 3.5 oder früher verwenden, ist Konrads Vorschlag, Calculate generisch zu machen, eine gute Wahl.

+0

Ich schätze die Zeit für die Antwort - es ist eine große Hilfe. – youwhut