#c# #.net #automapper
#c# #.net #automapper
Вопрос:
Возможно ли сопоставить исходный объект с конкретной реализацией целевого объекта с помощью automapper?
В следующем примере кода я хочу сопоставить from SourceItem
с to TargetSampleItem
, а не с to TargetBaseItem
. Важно: TargetBaseItem
не может быть абстрактным. Но если я использую следующую конфигурацию mapper, всегда TargetBaseItem
используется.
Подводя итог, следующая коллекция должна содержать элементы типа TargetSampleItem
, который выводится из TargetBaseItem
:
public IList<TargetItemBase> Items { get; set; } = new List<TargetItemBase>();
Полный код
using AutoMapper;
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MapperTest
{
class Program
{
static void Main(string[] args)
{
var configuration = new MapperConfiguration(cfg =>
{
cfg.CreateMap<SourceRoot, TargetRoot>();
cfg.CreateMap<SourceItem, TargetItemBase>()
.IncludeAllDerived();
});
configuration.AssertConfigurationIsValid();
var mapper = configuration.CreateMapper();
var source = new SourceRoot
{
Id = 1,
Items = new List<SourceItem>
{
new SourceItem { A = "a1", B = "b1" },
new SourceItem { A = "a2", B = "b2" }
}
};
var result = mapper.Map<TargetRoot>(source);
// Should retur true
Console.WriteLine(result.Items.First() is TargetSampleItem);
Console.ReadLine();
}
/// <summary>
/// Source model
/// </summary>
public class SourceRoot
{
public int Id { get; set; }
public IList<SourceItem> Items { get; set; } = new List<SourceItem>();
}
public class SourceItem
{
public string A { get; set; }
public string B { get; set; }
}
/// <summary>
/// Target model
/// </summary>
public class TargetRoot
{
public int Id { get; set; }
public IList<TargetItemBase> Items { get; set; } = new List<TargetItemBase>();
}
public class TargetItemBase
{
public string A { get; set; }
}
public class TargetSampleItem : TargetItemBase
{
public string B { get; set; }
}
}
}
Редактировать
использование As<>
не работает, потому что чем AutoMapper не сопоставляет с типом, а не просто приводит его:
cfg.CreateMap<SourceItem, TargetItemBase>()
.As<TargetSampleItem>();
РЕДАКТИРОВАТЬ 2 / Решение
Использование As<>
работает, если также добавляется сопоставление между SourceItem
и TargetSampleItem
:
cfg.CreateMap<SourceItem, TargetItemBase>().As<TargetSampleItem>();
cfg.CreateMap<SourceItem, TargetSampleItem>();
Комментарии:
1. Я не понимаю, если вы создаете сопоставление между
SourceItem
иTargetItemBase
, зачем AutoMapper создавать экземпляр TargetSampleItem ?2. Хороший момент, я попытался применить это с помощью Include<>, но не смог найти никакого рабочего решения
Ответ №1:
As
работает ли для меня:
cfg.CreateMap<SourceItem, TargetItemBase>().As<TargetSampleItem>();
cfg.CreateMap<SourceItem, TargetSampleItem>();
Комментарии:
1. Отлично, это работает. Раньше у меня это не работало, потому что я забыл вторую карту:
cfg.CreateMap<SourceItem, TargetSampleItem>();
Ответ №2:
Если As<>
это не работает для вас, то возможным решением может быть использование AfterMap
like —
CreateMap<SourceRoot, TargetRoot>()
.AfterMap((s, d) =>
{
s.Items.ToList().ForEach(p => d.TargetItems.Add(new TargetSampleItem { A = p.A, B = p.B }));
});
(Это не элегантное решение, но поскольку TargetSampleItem
оно не является целью ни одной из ваших карт, я не вижу никаких причин, по которым AutoMapper создавал бы его экземпляр).
Вы должны переименовать любое из Items
свойств, чтобы AutoMapper не пытался сопоставить их автоматически (я переименовал класс в TargetRoot
class TargetItems
). И, конечно, вам не нужно сопоставление между SourceItem
и TargetItemBase
.