Принудительное наследование VB.NET через несколько поколений

Я пытаюсь лучше обдумать наследование / интерфейсы / реализацию в.NET.

У меня есть класс, который определяется следующим образом (вроде):

Public Class Sheet
    Property Name As String
    Property Steps As List(Of [Step])
End Class

Дело в том, что [Step] - это просто виртуальный базовый класс. Существует 5 различных конкретных реализаций [Step]. Чтобы усложнить задачу, есть 3 ПРЯМЫХ реализации [Step], 2 из которых являются виртуальными. У каждого из этих 2 есть 2 подкласса, которые конкретно реализуют [Шаг].

Итак, вот как это выглядит:

                          Step
         |-----------------|-----------------|
         |                 |                 |
     SubStepA          SubStepB          SubStepC
    |----|----|                         |----|----|
    |         |                         |         |
SubStepAA SubStepAB                 SubStepCA SubStepCB

Итак, SubStepB, SubStepAA, SubStepAB, SubStepCA и SubStepCB являются конкретными реализациями.

Есть пара вещей, которые я бы хотел, чтобы ЛЮБОЙ Шаг сделал, например, Clone().

Итак, я попытался объявить следующее в шаге:

Public MustOverride Function Clone() As Step

Проблема в том, что, когда я пытаюсь реализовать это в SubStepAA, я не могу объявить следующее:

Public Overrides Function Clone() As SubStepAA

Если я это сделаю, я получу ошибку, что возвращаемые типы не совпадают.

Является ли решение этой проблемы просто использовать вызов DirectCast каждый раз, когда я клонирую конкретный подкласс? Это кажется странным и неудовлетворительным. Это также кажется неправильным. Я имею в виду, если я клонирую объект SubStepAA, я хочу вернуть объект типа SubStepAA.

Должен быть способ сделать это, верно? Я имею в виду, я думаю, что я мог бы просто объявить каждый класс таким, каким он должен быть, но также кажется неправильным писать 5 РАЗЛИЧНЫХ методов Clone (), которые просто ПРОИЗОЙДУТ работать (по существу) одинаково (создавая глубокую копию). указанного объекта).

Я смотрел на использование объявлений интерфейса, но, похоже, страдает от той же ошибки несоответствия типов.

Пожалуйста, скажите мне, что я просто упускаю что-то простое!

Спасибо!

Кроме того, я немного читаю и понимаю, что могут быть более оптимизированные способы создания глубоких копий объекта (например, посредством сериализации / десериализации), но я все еще интересуюсь этим вопросом, даже если я решу клонировать объекты, используя другой подход.

1 ответ

Возможно, это не совсем то, на что вы надеетесь, но вы можете удовлетворить все ваши требования, используя общий базовый тип, например так:

Public MustInherit Class [Step](Of T)
    Public MustOverride Function Clone() As T
End Class

Public Class StepA
    Inherits [Step](Of StepA)

    Public Overrides Function Clone() As StepA
        ' ...
    End Function
End Class

Однако тогда не было бы общего Step базовый класс, который будет использоваться для всех производных типов. Например, не было бы способа сделать что-то вроде этого:

Dim s As [Step] = New StepA()  'Won't work because there is no Step type, only a generic Step(T) type
Dim c As [Step] = s.Clone()

Однако, если вам нужен общий базовый тип, подобный этому, вы все равно можете сделать что-то подобное, хотя и с некоторыми дополнительными сложностями:

Public Interface ICloneable(Of T)
    Function Clone() As T
End Interface

Public MustInherit Class [Step]
    Implements ICloneable(Of [Step])

    Public MustOverride Function CloneBase() As [Step] Implements ICloneable(Of [Step]).Clone
End Class

Public MustInherit Class [Step](Of T As [Step])
    Inherits [Step]

    Implements ICloneable(Of T)

    Public Overrides Function CloneBase() As [Step]
        Return Clone()
    End Function

    Public MustOverride Function Clone() As T Implements ICloneable(Of T).Clone
End Class

Public Class StepA
    Inherits [Step](Of StepA)

    Public Overrides Function Clone() As StepA
        ' ...
    End Function
End Class

Если бы вы сделали это таким образом, у вас был бы тот дополнительный уровень абстракции, где вы могли бы привести каждый конкретный объект как Step(T) или как Step, Например, вы можете сделать это:

Dim s As [Step] = New StepA()
Dim c As [Step] = s.CloneBase()

Но, конечно, все это вызывает вопрос, стоит ли все это осложнение? Два более простых решения будут заключаться в том, чтобы реализовать интерфейс независимо для каждого производного класса (и, таким образом, отказаться от возможности вызывать клон из базового класса), или же пойти с вашей первой идеей и просто иметь Clone Метод всегда возвращает базовый тип.

Другие вопросы по тегам