2014-10-14 5 views
1

У меня есть один класс «timerecord» и два «секундомера» классов и «исторический», которые наследуются от этого класса, но не расширяют его с помощью каких-либо дополнительных свойств или методов. Их конструкторы просто устанавливают унаследованные свойства в разные вещи.конвертировать один производный класс в другой?

То, что я хочу быть в состоянии сделать, это преобразовать один тип наследуемых классов в другой тип (без ручного копирования всех свойств из одного в другой)

Я пробовал все типы ctype и directcast, но они не работают, я могу только вернуться к унаследованному классу, и это не то, что я хочу.

Классы идентичны во всех, кроме их имени. Я хочу, чтобы объект секундомера превратился в исторический объект.

Есть ли способ, которым я могу это сделать?

Если я реализую класс «timerecord», а также наследую? Или передать «timerecord» в конструкторы «секундомер» и «исторические» классы и использовать его как свойство или что-то еще?

Повесили мою голову об этом весь день и решили сделать учетную запись и спросить, поскольку я не могу найти ответ.

Tldr; Я хочу знать, как преобразовать один производный класс в другой идентичный (во всех, кроме имени) производный класс, и если это возможно?

Спасибо

+0

, если они идентичны, то почему бы не просто 'TypeCode' свойство, чтобы отличить одно от другого? Тогда преобразование было бы просто вопросом изменения кода. В противном случае перегрузка ctor, которая принимает другой тип, позволит вам создать один из другого. – Plutonix

+0

@ Jowijaro: добавьте пример кода на ваш вопрос !!! – umlcat

ответ

0

Если свойства такие же, вы можете сериализовать экземпляр stopwatch в строку затем десериализации его в historic инстанции.

Однако, я думаю, что лучшее решение будет иметь только timerecord класса с типом собственностью перечислений, которые используют бы иметь различие между stopwatch и historic экземпляром. Таким образом, вы можете передать перечисление типа timerecord в свой конструктор и установить свойство так, как вам нужно, в зависимости от значения перечисления.

0

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

Friend Enum TimeRecordTypes 
    Undefined 
    StopWatch 
    Historic 
End Enum 

Public Class TimeRecord 
    Public Property Name As String 
    Public Property Foo As Integer 
    Public Property Bar As DateTime 

    Public ReadOnly Property TimeRecordType As TimeRecordTypes = Undefined 
    ... 

    Public Sub New(e As TimeRecordTypes) 
     Select Case e 
      Case TimeRecordTypes.StopWatch 
       do stopwatch stuff 
      Case TimeRecordTypes.Historic 
       do Historic stuff 

     End Select 
    End Sub 

    Public Sub ConvertTo(maybe an arg for the type) 
     ' convert A to B 
    End Sub 
0

"(без ручного копирования всех свойств из одного в другой)"

В самом деле?
Я думаю, что в тот или иной момент вам придется писать более сложный код, делая это ...

Сериализовать/Deserialize ... удобный способ в большинстве случаев. Я использовал это .. до тех пор, пока я не добавил Свойство в класс, не добавляя их коллег в других. Классы типа Point2D с X и Y как двойной, Vector2D с X и Y как двойной или Displacement2D с X и Y как двойной ... до тех пор, пока я не добавил свойство Length в Vector2D ... и позже, Distance в Displacement2D ..:/

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

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


насчета Widening с CType?

Public Class StopWatch 
    Inherits TimeRecord 

    ' ... 

    Public Shared Widening Operator CType(ByVal HistoricInstance As Historic) As StopWatch 
     Dim NewStopWatch As StopWatch 
     If HistoricInstance IsNot Nothing Then 
      NewStopWatch = New StopWatch(...) 
      ' Set NewStopWatch Properties here... 
      ' ... 
      Return NewStopWatch 
     Else 
      Return Nothing 
     End If 
    End Operator 
End Class 

И:

Public Class Historic 
    Inherits TimeRecord 

    ' ... 

    Public Shared Widening Operator CType(ByVal StopWatchInstance As StopWatch) As Historic 
     Dim NewHistoric As Historic 
     If StopWatchInstance IsNot Nothing Then 
      NewHistoric = New Historic(...) 
      ' Set NewHistoric Properties here... 
      ' ... 
      Return NewHistoric 
     Else 
      Return Nothing 
     End If 
    End Operator 
End Class 

Примечание: При добавлении свойства в StopWatch, но не исторический, оператор Секундомер CType становится Сужение один вместо Widening.

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

Предположим, что у вас есть класс MyStopWatch типа StopWatch и свойство InitializationDateTime, которое установлено в Date . Теперь в конструкторе ..

MyStopWatch = New StopWatch() ' .InitializationDateTime = Date.Now 
' do some stuff... 
MyHistoric = CType(MyStopWatch, Historic) ' where MyHistoric.InitializationDateTime = Date.Now 

С вышеуказанным кодом у вас будут различные значения свойства Initializ ationDateTime, даже если вы предполагаете, что правильно выбрали MyTimeRecord для MyHistoric, это связано с тем, что CType создал экземпляр Historic на позже, чем когда инициализирован MyTimeRecord.

Итак, как? Сериализация, свойство TypeCode/Enum или расширение CType?

Plutonix есть еще один способ:

Public Class StopWatch() 
    Public Sub New(ByVal HistoricInstance As Historic) 
     ' Copy Properties values here... 
    End Sub 
End Class 
' Do the same for Historic Class. 

Или вы можете также сделать функции (VB.net смысл)

Public Class StopWatch() 
    Public Function ToHistoric() As Historic 
     Dim NewHistoric As New Historic() 
     ' .. set NewHistoric Properties values here 
     Return NewHistoric 
    End Function 
End Class 

Но результат тот же: вам придется писать код задайте значения свойств один за другим. Хорошая вещь: вы пишете код один раз, в конечном итоге обновляете его, но можете использовать его в любое время только с одной строкой кода ...

DirectCast удобен, но подвержен краху во время выполнения.
TryCast смешно, но вам все равно придется проверять провал кастинга. :/

Есть еще другие способы сделать это, но с этого времени один из предложенных способов достаточно полезен или у вас есть определенные требования, например, проблема выше?

+0

Расширение похоже, что оно будет работать для меня. По причинам, не зависящим от меня, система, с которой я работаю, использовала две коллекции одного типа. Одна коллекция хранит текущие секундомеры, а другая хранит исторический. Единственное различие между типами - это коллекция, в которой они находятся. Чтобы изменить это, я хотел иметь один ключевой набор базового типа и создать производный тип, который я указываю для добавления в коллекцию, а не только один общий тип. – Jowijaro

+0

Трудность возникла, когда мне нужно было воспроизвести переход от «секундомера» к «историческим» определениям «timerecord». Поскольку это было сделано ранее, удалив элемент из коллекции секундомера в историческую коллекцию, я решил, что в своей коллекции я бы смог просто преобразовать один тип в другой. Конверсия Widening позволит мне это сделать – Jowijaro

+0

Теперь у меня есть тип «секундомера», который может быть преобразован в «исторический» тип, когда он стареет, как это было в старой системе. Но таким образом я использую только одну строго типизированную коллекцию и могу использовать Inheritance для разделения типов, это делает код намного чище и проще для понимания того, что создается, а также облегчает мне поддержку, и на самом деле это очень много меньше кода, чем оригинал. Спасибо. – Jowijaro

0

Я попробовал предоставленные решения и при этом понял, что решение не использует наследование, но вместо этого, поскольку они являются точно такими же, но с разными именами, для использования интерфейса. Я создал интерфейс, а также другой класс basetimerecord, все три класса реализуют этот интерфейс. Свойства basetimerecord указывают на переменные.

Другие свойства классов указывают на свойства частной переменной типа basetimerecord. Базисное оформление публикуется через общедоступное свойство, доступное только для чтения. Конструкторы каждого из этих классов могут принимать basetimerecord в качестве параметра. Когда они это делают, они переопределяют свою собственную переменную с этим, поэтому я могу скопировать все свойства, изменяя только одну личную переменную каждый раз.

я теперь могу сделать исторический = новый исторический (stopwatch.basetimerecord)

Смежные вопросы