Преобразовать класс в производный класс - PullRequest
3 голосов
/ 13 февраля 2012

Есть ли способ преобразовать базовый класс в его производный класс?

Вот простой пример двух классов:

namespace BLL
{
    public class Contact 
    {
       public int ContactID { get; set; }
       public string Name { get; set; }

       public Contact(){}
    }
}

namespace BLL
{
    public class SpecialContact : Contact
    {
       public SpecialContact(){}
    }
}

В идеале я мог бы сделать что-то вроде этого:

Contact contact = new Contact();
SpecialContact specialContact = new SpecialContact();

contact.ContactID = 123;
contact.Name = "Jeff";

specialContact = contact;

Этот код, конечно, выдает ошибку.Кроме написания другого конструктора для SpecialContact или метода, который устанавливает каждое свойство, есть ли другое решение?

Ответы [ 5 ]

3 голосов
/ 13 февраля 2012

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

Ваш конкретный пример будет выглядеть так:

Mapper.CreateMap<Contact, SpecialContact>();
Contact contact = new Contact();
contact.ContactID = 123;
contact.Name = "Jeff";
SpecialContact specialContact = Mapper.Map<Contact, SpecialContact>(contact);
3 голосов
/ 13 февраля 2012

Недопустимо присваивать Base ссылку на класс на Derived переменную ссылки на класс.

Переменная типа X может быть только ссылкой на объект типа X или производным.

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

Я использую следующий метод расширения, когда мне нужно скопировать совпадающие свойства из одного несовместимого объекта в другой (1):

public static void AssignFrom(this object destination, object source) {
  Type dest_type = destination.GetType();
  Type source_type = source.GetType();

  var matching_props = from d in dest_type.GetProperties()
                        join s in source_type.GetProperties()
                        on d.Name equals s.Name
                        where d.IsWritable() && s.IsReadable()
                        select new {
                          source = s,
                          destination = d
                        };

  foreach (var prop in matching_props) {
    prop.destination.SetValue(destination, prop.source.GetValue(source, null), null);
  }
}

Тогда вы можете сделать:

specialContact.assignFrom(contact);

Пожалуйста, рассмотрите это как обходной путь. Правильным решением будет правильно спроектировать иерархию классов, в которой вы не решите эту проблему.


1 Примечание: сопоставляет свойства по имени и предполагает, что они относятся к одному типу.

2 голосов
/ 13 февраля 2012

Помимо написания другого конструктора для SpecialContact или метода, который устанавливает каждое свойство, есть ли другое решение?

Нет, не совсем.
Вы можете автоматизировать его с помощью Reflection, ноэто об этом.

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

Если контракты могут со временем преобразоваться в SpecialContracts, то вы либо создаете новый объект, либо моделируете его с помощью свойства ContactType и, возможно, некоторой композиции.

1 голос
/ 13 февраля 2012

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

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

Что касается преобразования иерархии наследования, вы можете использовать Pattern Design Decorator для добавления специальных функций в ваш класс Contact, предоставляя ему функциональность SpecialContact без подклассов.

1 голос
/ 13 февраля 2012

Этот код, конечно, выдает ошибку.Помимо написания другого конструктора для SpecialContact или метода, который устанавливает каждое свойство, есть другое решение?

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...