Как преобразовать пользовательский сложный тип в другой пользовательский сложный тип - PullRequest
8 голосов
/ 14 января 2011

Итак, у меня есть два пользовательских сложных типа, подобных этому (упрощенно для этого примера):

public class PendingProduct
{
    public string Name { get; set; }
    public string Description { get; set; }
    public int ColorCount { get; set; }
}

Допустим, мне нужен этот объект, чтобы знать, как преобразовать себя в другой тип:

public class Product
{
    public string Name { get; set; }
    public string Description { get; set; }
    public ProductColors Colors { get; set;}
}

Поэтому, когда я вызываю метод для преобразования PendingProduct в Product, я выполняю некоторую пользовательскую логику, которая добавляет число «ColorCount» объектов ProductColor в класс Product. Это полностью упрощено, но архитектура класса здесь действительно не имеет значения.

Мой главный вопрос:

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

В реальном мире свойства очень разные, и я напишу некоторую пользовательскую логику, чтобы сопоставить то, что мне нужно, от Объекта А к Объекту Б.

Очевидно, что я мог бы просто написать функцию, которая принимает входной параметр объекта A и возвращает объект B, но я ищу более эффективный метод. IConvertible вступает в игру здесь? Есть ли что-то более похожее на ООП, которым я могу воспользоваться, а не просто написать функцию, которая делает то, что я хочу?

Объект A всегда должен знать, как преобразовать себя в Объект B.

РЕДАКТИРОВАТЬ: В качестве примечания, в реальном мире, Объект A и Объект B являются сущностями Entity Framework 4. Я хочу взять «Ожидающий продукт», преобразовать его в новую сущность «Продукт», присоединить к контексту данных и сохранить.

Ответы [ 2 ]

19 голосов
/ 14 января 2011

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

Я добавлю его сюда для справки:

Реально вы могли бы

1. Отражение

public void Map<TSource, TDestination>(TSource source, TDestination destination)
{
  var props = typeof(TSource).GetProperties(BindingFlags.Public | BindingFlags.Instance);
  var type = typeof(TDestination);

  foreach (var prop in props)
  {
    object value = prop.GetValue(source, null);

    var prop2 = type.GetProperty(prop.Name);
    if (prop2 == null)
      continue;

    if (prop.PropertyType != prop2.PropertyType)
      continue;

    prop2.SetValue(destination, value, null);
  }
}

2. Конструктор копирования

public Employee(Person person)
{
  // Copy properties
}

3. Явное / явное преобразование

public static implicit operator Employee(Person person)
{
  // Build instance and return
}

4.AutoMapper

Mapper.Map<Person, Employee>(person);

5.Комбинация 3/4:

public static implicit operator Employee(Person person)
{
  return Mapper.Map<Person, Employee>(person);
}

Примечание по операторам неявного / явного преобразования: я уверен, что при их использовании вы не будете генерировать CLS-совместимый код.

AutoMapper позволяет вам настраивать отображение различных свойств целевого типа, например:

Mapper.CreateMap<Person, Employee>()
      .ForMember(e => e.Forename, o => o.MapFrom(p => p.Forename.ToLower()));
0 голосов
/ 14 января 2011

Не хотите ли вы получить PendingProduct из продукта?

public class Product 
{     
  public string Name { get; set; }     
  public string Description { get; set; }     
  public ProductColors Colors { get; set; } 
} 

public class PendingProduct : Product 
{         
  public int ColorCount { get; set; } 
}
...