Путаница - реализованный интерфейс нуждается в кастинге? - PullRequest
3 голосов
/ 12 января 2011

У меня есть класс Entity, который реализует 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. Instantiateколлекция сущностей Dim entites As New List(Of Entity)
  2. Создание экземпляров WeightsCalculator Dim wc As New WeightsCalculator(...)

Почему я не могу сделать wc.Calculate (entity)?Я получаю:

Невозможно привести объект типа 'System.Collections.Generic.List 1[mynameSpace.Entity]' to type 'System.Collections.Generic.IList 1 [myNamespace.IWeightable]'.

Если Entity реализует IWeightableпочему это невозможно?

Ответы [ 2 ]

6 голосов
/ 12 января 2011

A 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 имеет частичное решение для этого в виде универсальной дисперсии .Если ваш Calculate метод выполняет итерации только по entities, вы можете изменить подпись следующим образом:

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

Хотя IList(Of T) является инвариантом , IEnumerable(Of T) является ковариантный в T, поскольку API только когда-либо позволяет значениям T быть возвращаемыми им - в методах IEnumerable(Of T) нет параметров типа T.Так что есть преобразование из List(Entity) в IEnumerable(Of IWeightable).

Общая дисперсия - тема волосатая - на NDC 2010 я выступил с презентацией по ней, которая может оказаться вам полезной.Вы можете посмотреть его на странице видео NDC 2010 .(Ищите «дисперсия».)

Если вы используете .NET 3.5 или более раннюю версию, предложение Конрада сделать Calculate generic является хорошим выбором.

6 голосов
/ 12 января 2011

Это не работает.

Предположим, у вас есть другой класс, 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...