将基数 class 映射到集合的具体实现
Map base class to specific implementation for collections
是否可以使用自动映射器从源对象映射到目标对象的特定实现?
在下面的代码示例中,我想从 SourceItem
映射到 TargetSampleItem
而不是 TargetBaseItem
。重要提示:TargetBaseItem
不能是抽象的。但是,如果我使用以下映射器配置,则始终使用 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>();
如果 As<>
对您不起作用,那么可能的解决方案可能是使用 AfterMap
,例如 -
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
之间的映射。
As
对我有用:
cfg.CreateMap<SourceItem, TargetItemBase>().As<TargetSampleItem>();
cfg.CreateMap<SourceItem, TargetSampleItem>();
是否可以使用自动映射器从源对象映射到目标对象的特定实现?
在下面的代码示例中,我想从 SourceItem
映射到 TargetSampleItem
而不是 TargetBaseItem
。重要提示:TargetBaseItem
不能是抽象的。但是,如果我使用以下映射器配置,则始终使用 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>();
如果 As<>
对您不起作用,那么可能的解决方案可能是使用 AfterMap
,例如 -
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
之间的映射。
As
对我有用:
cfg.CreateMap<SourceItem, TargetItemBase>().As<TargetSampleItem>();
cfg.CreateMap<SourceItem, TargetSampleItem>();