Изменение типа поля в C # во время выполнения - PullRequest
1 голос
/ 09 ноября 2009

У меня есть существующая иерархия классов, скажем что-то вроде этого:

Business
  - Division
    - ProjectTeam
      - Employee

Эти классы создаются с помощью десериализации.

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

SpecialBusiness (extends Business)
  - Division
    - ProjectTeam
      - SpecialEmployee (extends Employee)
        - Degree

Проблема в том, что я не могу просто создать класс, который расширяет класс «Бизнес», потому что я хочу добавить класс «Сотрудник».

На мой взгляд, у меня есть два варианта:

  1. Дублируйте иерархию со специальными классами. Это означает, что каждый «Специальный» класс будет иметь коллекцию исходных классов и коллекцию новых «Специальных» классов.

    SpecialBusiness
      - Division AND SpecialDivision (extends Division)
        - ProjectTeam AND SpecialProjectTeam (extends ProjectTeam)
          - Employee AND SpecialEmployee (extends Employee)
            - Degree
    
  2. Каким-то образом введите «Employee» в «SpecialEmployee» во время выполнения для целей десериализации. Знайте, что я могу преобразовать все объекты Employee из SpecialBusiness в SpecialEmployee в кодовой базе (возможно, используя вспомогательные методы, чтобы сделать это очевидным).

Есть идеи как решить эту проблему?

Ответы [ 7 ]

1 голос
/ 09 ноября 2009

Почему вы не можете использовать исходный код для десериализации для создания экземпляров классов, которые вы хотите во время выполнения?

1 голос
/ 15 ноября 2009

Когда в XML указаны действительные типы объектов:

  <Employees>
    <Employee>
      <Name>Bob</Name>
    </Employee>
    <Employee xsi:type="SpecialEmployee">
      <Name>Carol</Name>
      <Degree>Chief</Degree>
    </Employee>
  </Employees>

по крайней мере при отстранении от объявленного типа (здесь Employee [] Employees) XMLSerializer хорошо поддерживает полиморфизм при десериализации, так как он создаст SpecialEmployee с Name = "Carol" и Degree = "Chief"; данный SpecialEmployee является производным от Employee, а XMLSerializer сообщается об этом.
Это можно сделать с помощью атрибута XmlInclude или путем предоставления специализированных типов при создании XMLSerializer.

1 голос
/ 09 ноября 2009

Большинство платформ сериализации, например XmlSerializer и BinaryFormatter предоставляют способы десериализации потоков пользовательским способом, чтобы вы могли иметь обновленную / новую иерархию и десериализовать старые потоки в нее. Какую платформу сериализации вы используете?

1 голос
/ 09 ноября 2009

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

1 голос
/ 09 ноября 2009

Ну, я не совсем уверен, подходит ли это в вашей ситуации, но посмотрите на мой ответ для на этот вопрос . Вы можете получить классы Division и Employee из Decorable и получить SpecialDivision и SpecialEmployee из Decorator<Division> и Decorator<Employee>.

1 голос
/ 09 ноября 2009

Вы не можете изменить тип поля во время выполнения.

Тем не менее, почему вы не можете просто расширить сотрудника, если это то, что вы хотите сделать? Полиморфизм утверждает, что вы можете вставить объект подтипа в поле его супертипа? Зачем вам нужно переписывать родительский объект?

0 голосов
/ 09 ноября 2009

Одно из возможных решений (предполагается, что выбранный метод десериализации допускает сериализацию частного поля):

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

SpecialProjectTeam
  - (private) SpecialEmployees
  - (public) Employees
  - (public) GetSpecialEmployees (returns Employees field cast as SpecialEmployees)
...