Передача списка (из дочернего класса) в качестве параметра методу, ожидающему списка (из родительского класса)?

Я реализовал наследование для двух родительских классов, названных Table и Field. Каждый родительский класс имеет несколько дочерних классов. В родительском классе Table я создал метод, который ожидает параметр List(Of Field).

Я получаю сообщение об ошибке при попытке передать параметр List(Of ChildField) методу, который ожидает параметр List(Of Field). Сообщение об ошибке выглядит следующим образом:

Значение типа «System.Collections.Generic.List(Of com.hlb.icisbatch.data.ChildField)»
не может быть преобразовано в «System.Collections.Generic.List(Of com.hlb.icisbatch.data.Field)». )'

Мой вопрос, можно ли передать список дочерних классов в качестве параметра? Если это не список, то он работает нормально. А со списками как-то не получается?

Ниже приведен пример структуры класса:

    Table              Field
      |                  |
  ChildTable         ChildField

У меня есть метод в родительском классе:

Public Class Table

    Public Sub New()
    End Sub

    Public Overridable Sub setFields(ByVal list As List(Of Field)
       'Do work here'
    End Sub

 End Class

и метод в дочернем классе:

Public Class ChildTable

    Public Sub New(ByVal list As List(Of ChildField)
       setFields(ChildField)
    End Sub

 End Class

person Nicholas    schedule 12.04.2010    source источник


Ответы (2)


Нет, это невозможно - и на то есть веские причины. Подумайте, что произойдет, если вызывающий код попытается добавить в список экземпляр Field (или другого производного класса). Произойдут плохие вещи.

В .NET 4 (и, предположительно, VB10) это возможно благодаря ковариантности и контравариантности универсальных делегатов и интерфейсов (не классов), но только там, где это безопасно. Таким образом, IList(Of T) не является не вариантом (поскольку значения входят и выходят из API); IEnumerable(Of T) является ковариантным (так что есть преобразование из IEnumerable(Of String) в IEnumerable(Of Object)), а IComparer(Of T) контравариантно (например, есть преобразование из IComparer(Of Object) в IComparer(Of String)).

(На самом деле эта возможность была в CLR начиная с версии 2.0, но она появилась только в языках и инфраструктуре для .NET 4.)

person Jon Skeet    schedule 12.04.2010

Итак, для .Net 4.0+ (возможно, и более ранних версий) вам придется изменить метод setFields:

Public Overridable Sub setFields(As T Of Field)(ByVal list As List(Of T)
   'Do work here'
End Sub

Затем, когда вы вызываете его с помощью:

Public Sub New(ByVal list As List(Of ChildField)
   setFields(list)
End Sub

по сути он вызывает:

setFields(Of ChildField)(list)

это означает, что setFields знает, что имеет дело со списком объектов ChildField, и никому не позволит сделать что-нибудь непослушное, например, добавить другой объект ChildNumber2Field.

Хотя дженерики были представлены в .Net 2.0, я точно не знаю, насколько продвинутой была эта версия, чтобы делать такие вещи.

person monty    schedule 26.02.2018