AutoMapper(六)

返回总目录


List和数组

AutoMapper只要求元素类型的配置而不要求可能会用到的任何数组或者list类型。比如,我们有一个简单的源和目标类型:

public class Source
{
    public int Value { get; set; }
}

public class Destination
{
public int Value { get; set; }
}

支持所有的基本泛型集合,代码如下:

class Program
{
    static void Main(string[] args)
    {
        Mapper.CreateMap<Source, Destination>();
        var sources = new[]
        {
            new Source() {Value = 1},
            new Source() {Value = 2},
            new Source() {Value = 3},
        };
        IEnumerable<Destination> iEnumerableDests= Mapper.Map<IEnumerable<Destination>>(sources);
        ICollection<Destination> iCollectionDests= Mapper.Map<ICollection<Destination>>(sources);
        IList<Destination> iListDests= Mapper.Map<IList<Destination>>(sources);
        List<Destination> listDests= Mapper.Map<List<Destination>>(sources);
        Destination[] destsArr= Mapper.Map<Destination[]>(sources);
        //这里只举两个例子,其他集合同理
        foreach (var dest in iCollectionDests)
        {
            Console.Write(dest.Value+",");
        }
        Console.WriteLine();
        foreach (var dest in destsArr)
        {
            Console.Write(dest.Value + ",");
        }
    Console.Read();
}

}

以上代码是集合和集合之间的映射,但是映射的配置CreateMap方法中只是配置的是类型之间的映射,而没有设计任何集合类型。

测试结果如下,可见集合之间映射成功:

image

具体来说,支持的源集合类型包括:

  • IEnumerable
  • IEnumerable<T>
  • ICollection
  • ICollection<T>
  • IList
  • IList<T>
  • List<T>
  • Arrays

集合中的多态元素类型

很多时候,在我们的源和目标类型中可能有一个类型层次关系。AutoMapper支持多态数组和集合,因此如果发现派生的源或者目标类型,就会使用它们。

public class ParentSource
{
    public int Value1 { get; set; }
}

public class ChildSource : ParentSource
{
public int Value2 { get; set; }
}

public class ParentDestination
{
public int Value1 { get; set; }
}

public class ChildDestination : ParentDestination
{
public int Value2 { get; set; }
}

AutoMapper仍然要求显示配置孩子映射,因为它不能“猜出”具体使用哪一个孩子目标映射。

在Main方法中添加如下代码:

Mapper.Initialize(c =>
{
    c.CreateMap<ParentSource, ParentDestination>()
        .Include<ChildSource, ChildDestination>();
    c.CreateMap<ChildSource, ChildDestination>();
});
var sources = new[]
{
    new ParentSource(){Value1 = 11},
    new ChildSource(){Value2 = 22},
    new ParentSource(),
};

var dests = Mapper.Map<ParentDestination[]>(sources);
Console.WriteLine(dests[
0]);
Console.WriteLine(dests[
1]);
Console.WriteLine(dests[
2]);

测试结果如下:

image

上面我们创建了一个源的数组,其中包含两个ParentSource和一个ChildSource,所以两个ParentSource成功地映射到了ParentDestination,而CreateMap配置中,ParentSource到ParentDestination的映射配置包含了ChildSource到ChildDestination的配置,所以执行Mapper.Map<ParentDestination[]>(sources)的时候,也可以将ChildSource映射到ChildDestination。

映射继承

在派生类中标明继承

上面的代码,是在基类中配置继承的,除此之外,也可以在派生类中配置继承:

//在基类中配置继承
 Mapper.Initialize(c =>
 {
     c.CreateMap<ParentSource, ParentDestination>()
         .Include<ChildSource, ChildDestination>();
     c.CreateMap<ChildSource, ChildDestination>();
 });
 //在派生类中配置继承
 Mapper.Initialize(c =>
 {
     c.CreateMap<ParentSource, ParentDestination>();
     c.CreateMap<ChildSource, ChildDestination>()
         .IncludeBase<ParentSource, ParentDestination>();
 });

继承映射属性

这里介绍一下额外的复杂性,因为一个属性映射时可以有多种方式。下面是这些源的优先级:

  • 显式映射 (使用.MapFrom())
  • 继承的显式映射 
  • 惯例映射 (通过惯例匹配的属性)
  • 忽略的属性映射

下面来演示一下:

这里还是用上面定义的四个类:Order,OrderDto,PCOrder,MobileOrder:

//领域对象
public class Order { }
//电脑端订单
public class PCOrder : Order
{
    public string Referrer { get; set; }
}
//手机订单
public class MobileOrder : Order { }

//Dtos
public class OrderDto
{
public string Referrer { get; set; }
}

配置映射的方法使用的是在父类中配置继承映射

//在父类中配置继承映射
Mapper.CreateMap<Order, OrderDto>()
    .Include<PCOrder,OrderDto>()
    .Include<MobileOrder,OrderDto>()
    .ForMember(o => o.Referrer, m => m.Ignore());//这里配置了忽略目标属性Referrer的映射
Mapper.CreateMap<PCOrder,OrderDto>();
Mapper.CreateMap<MobileOrder, OrderDto>();
// 执行映射
var order = new PCOrder() { Referrer = "天猫" };
var mapped = Mapper.Map<OrderDto>(order);
Console.WriteLine(mapped.Referrer);

执行结果如下:

image

注意在我们的映射配置中,我们已经忽略了Referrer(因为Order基类中不存在这个属性),但是在基类的映射中,惯例比忽略的属性有更高的优先级,因而属性仍然得到了映射。

posted @ 2015-11-07 12:02  tkbSimplest  阅读(3644)  评论(1编辑  收藏  举报