Создание объекта производного класса из объекта базового класса

#c# #architecture #tree

#c# #архитектура #дерево

Вопрос:

в моем приложении у меня древовидная структура данных. Узлы относятся к классу X. У меня есть другой класс Y, который является производным от X. В конце концов, мне нужно «преобразовать / изменить» узлы с типа X на тип Y — во всей древовидной структуре.

Есть ли простой способ сделать это или мне нужно проанализировать все дерево, воссоздав его, создав экземпляр каждого узла с типом Y?

Заранее спасибо,
Фрэнк

Эдит говорит: Спасибо за все ваши ответы! Я пытаюсь объяснить, зачем мне нужно такое поведение: Давайте представим, что мы поставщик провизии. Мы хотим смоделировать наше портфолио в виде дерева. Одним узлом может быть «soups», и мы предлагаем картофельные супы, томатные супы и супы с лапшой — каждый из них является дочерним узлом узла «soups». После завершения моделирования мы представляем дерево клиенту, который выбирает «базовую службу общественного питания». Это означает, что она может выбрать один из супов на свой ужин.
Для моей базовой модели это означает, что мне нужно дополнительное поле «IsSelected», которое мне не нужно, когда поставщик услуг создает портфолио. Итак, я хочу вывести класс Y из класса X с дополнительным полем.

Комментарии:

1. Ваш вопрос не совсем ясен. Не могли бы вы предоставить некоторую справочную информацию, пожалуйста? Зачем вам это нужно делать?

Ответ №1:

Да, вам придется пройти по всему дереву и заново создать все узлы.

Что делает хорошей идеей пересмотреть дизайн, который привел к этой ситуации.

Комментарии:

1. Да, я добавил слой к дизайну. Когда я перехожу в режим «конфигурация», я соответствующим образом меняю слои.

Ответ №2:

Фактический тип объекта определяется при его создании и не может быть изменен впоследствии. Так что нет, другого способа нет.

Ответ №3:

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

Но в любом случае вам обычно приходится обходить все дерево, чтобы изменить стратегию на каждом узле. Если действительно поведение всех объектов должно измениться, вы также могли бы подумать о комбинации с шаблоном проектирования Flyweight. Но, как уже упоминалось, здесь слишком мало информации, чтобы дать хороший совет.

Ответ №4:

Возможно, вам может помочь неявное или явное приведение оператора, но я думаю, что к этому приводит какой-то плохой дизайн:

 public static implicit operator MyTypeB( MyTypeA a ) {
  MyTypeB b = new MyTypeB();
  // copy all a properties
  return b;
}
  

Люди говорят, что вам нужно было бы зациклить и воссоздать все узлы, но таким образом все узлы можно использовать как узлы другого типа, потому что они выполняют работу по воссозданию при необходимости.

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

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

Ответ №5:

Потому что никто еще не указал на это…

Если вы создаете объект как Y , он может быть приведен к X , а затем обратно к Y снова, но объект, созданный как X , не может быть приведен к Y . Это всего лишь базовое поведение OO.

Это означает, что если вы создаете свой источник данных в виде иерархического списка Y , вы можете затем привести их к X , а затем обратно к Y , когда это удобно.

На самом деле, если вы используете Linq, для класса Enumerable существует метод расширения, который называется Cast(). Вы можете использовать это следующим образом:

 public class Animal {   }

public class Dog : Animal {   }

List<Dog> dogs = new List<Dog>();
List<Animal> animals = dogs.Cast<Animal>().ToList();
  

Вы не упомянули, что вы используете (WinForms / WPF / Silverlight / ASP.NET), но WPF имеет HierarchicalDataTemplate, который вы можете привязать к списку, подобному node (т. Е. у каждого элемента в списке могут быть дочерние элементы). Использование чего-то подобного с Cast() из приведенного выше должно хорошо работать.

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