Рекомендации по сопоставлению одного объекта с другим
Мой вопрос: какой лучший способ я могу сопоставить один объект с другим наиболее удобным образом. Я не могу изменить способ, с помощью которого объект Dto, который мы получаем, является более нормализованным, поэтому мне нужно создать способ сопоставить это с нашей реализацией их объекта.
Вот пример кода, чтобы показать, что мне нужно:
class Program
{
static void Main(string[] args)
{
var dto = new Dto();
dto.Items = new object[] { 1.00m, true, "Three" };
dto.ItemsNames = new[] { "One", "Two", "Three" };
var model = GetModel(dto);
Console.WriteLine("One: {0}", model.One);
Console.WriteLine("Two: {0}", model.Two);
Console.WriteLine("Three: {0}", model.Three);
Console.ReadLine();
}
private static Model GetModel(Dto dto)
{
var result = new Model();
result.One = Convert.ToDecimal(dto.Items[Array.IndexOf(dto.ItemsNames, "One")]);
result.Two = Convert.ToBoolean(dto.Items[Array.IndexOf(dto.ItemsNames, "Two")]);
result.Three = dto.Items[Array.IndexOf(dto.ItemsNames, "Three")].ToString();
return result;
}
}
class Dto
{
public object[] Items { get; set; }
public string[] ItemsNames { get; set; }
}
class Model
{
public decimal One { get; set; }
public bool Two { get; set; }
public string Three { get; set; }
}
Я думаю, что было бы здорово, если бы у меня был какой-то класс сопоставления, который бы взял в объектах model propertyInfo, тип, который я хочу преобразовать, и "itemname", который я хочу вытащить. Есть ли у кого-нибудь какие-либо предложения сделать это чище?
Спасибо!
Ответы
Ответ 1
Я бы выбрал AutoMapper, библиотеку с открытым исходным кодом и бесплатную картографию, которая позволяет сопоставлять один тип с другим, на основе условностей ( т.е. отображать общедоступные свойства с одинаковыми именами и одинаковыми/производными/конвертируемыми типами, а также со многими другими умными). Очень проста в использовании, позволит вам добиться чего-то вроде этого:
Model model = Mapper.Map<Model>(dto);
Не уверен в ваших конкретных требованиях, но AutoMapper также поддерживает настраиваемые переменные значения, которые должны помочь вам написать единую, общую реализацию вашего конкретного картограф.
Ответ 2
Это возможная общая реализация, использующая бит отражения (псевдокод, теперь нет VS):
public class DtoMapper<DtoType>
{
Dictionary<string,PropertyInfo> properties;
public DtoMapper()
{
// Cache property infos
var t = typeof(DtoType);
properties = t.GetProperties().ToDictionary(p => p.Name, p => p);
}
public DtoType Map(Dto dto)
{
var instance = Activator.CreateInstance(typeOf(DtoType));
foreach(var p in properties)
{
p.SetProperty(
instance,
Convert.Type(
p.PropertyType,
dto.Items[Array.IndexOf(dto.ItemsNames, p.Name)]);
return instance;
}
}
Использование:
var mapper = new DtoMapper<Model>();
var modelInstance = mapper.Map(dto);
Это будет медленным, если вы создадите экземпляр mapper, но намного быстрее.
Ответ 3
/// <summary>
/// map properties
/// </summary>
/// <param name="sourceObj"></param>
/// <param name="targetObj"></param>
private void MapProp(object sourceObj, object targetObj)
{
Type T1 = sourceObj.GetType();
Type T2 = targetObj.GetType();
PropertyInfo[] sourceProprties = T1.GetProperties(BindingFlags.Instance | BindingFlags.Public);
PropertyInfo[] targetProprties = T2.GetProperties(BindingFlags.Instance | BindingFlags.Public);
foreach (var sourceProp in sourceProprties)
{
object osourceVal = sourceProp.GetValue(sourceObj, null);
int entIndex = Array.IndexOf(targetProprties, sourceProp);
if (entIndex >= 0)
{
var targetProp = targetProprties[entIndex];
targetProp.SetValue(targetObj, osourceVal);
}
}
}