zoukankan      html  css  js  c++  java
  • AutoMapper(一)

    返回总目录


    映射前后操作

    偶尔有时候,在映射发生之前或之后,你可能需要执行一些自定义的逻辑。这可能是很少见的事情,因为在AutoMapper之外处理这些事情是更明显的。你可以创建一个映射前后的全局操作:

    Mapper.CreateMap<Source, Dest>()
        .BeforeMap((src, dest) => src.Value = src.Value + 10)
        .AfterMap((src, dest) => dest.Name = "John");

    或者在映射期间,创建映射前后的回调函数:

    int i = 10;
    Mapper.Map<Source, Dest>(src, opt => {
        opt.BeforeMap((src, dest) => src.Value = src.Value + i);
        opt.AfterMap((src, dest) => dest.Name = HttpContext.Current.Identity.Name);
    });

    当你需要将上下文信息注入映射前后的行为中时,后者的配置很有用。

    条件映射

    在属性映射之前,AutoMapper允许将必须满足的条件添加到属性上。

    这个用在下面这种情况,比如有两个类,分别是Aliens(外星人)和Person(人)类,都有一个Age属性,我们都知道我们人类的年龄都是非负数,所以我们这里用unsigned int(无符号整数)类型。但是,目前人类科技水平有限,还没有研究出是否有外星人存在,就更无法确定其年龄属性了,所以我们这里假设外星人的年龄可以为负数(如果你反驳我你也没依据啊,暂且就这样吧),那么就定义其为int类型,如果我们要将外星人映射到人类上,其实就是uint到int之间的映射:

    namespace FrontAutoMapper
    {
        class Program
        {
            static void Main(string[] args)
            {
    //创建映射,映射条件是源类型的Age属性在区间(0,149)范围内
                Mapper.CreateMap<Aliens, Person>().ForMember(dest => dest.Age, opt => opt.Condition(src => src.Age > 0 && src.Age < 149));
    
                var p1 = Mapper.Map<Person>(new Aliens() { Age = -1 });//不符合映射条件
                  var p2 = Mapper.Map<Person>(new Aliens() { Age = 0 });//不符合映射条件
                  var p3 = Mapper.Map<Person>(new Aliens() { Age = 1 });//符合映射条件
                  var p4 = Mapper.Map<Person>(new Aliens() { Age = 148 });//符合映射条件
                  var p5 = Mapper.Map<Person>(new Aliens() { Age = 149 });//不符合映射条件
                  Console.WriteLine(p1.Age);//映射不成功,返回Person.Age默认值22
                Console.WriteLine(p2.Age);//映射不成功,返回Person.Age默认值22
                Console.WriteLine(p3.Age);//映射成功,返回新值1
                Console.WriteLine(p4.Age);//映射成功,返回新值148
                Console.WriteLine(p5.Age);//映射不成功,返回新值22
                Console.Read();
            }
        }
        public class Person
        {
            public Person()
            {
                Age = 22;
            }
            public uint Age { set; get; }//Person的Age属性默认值是22
        }
    
        public class Aliens
        {
            public Aliens()
            {
                Age = -23;
            }
            public int Age { get; set; }//Aliens的Age属性默认值是-23
        }
    }

    这个例子是将年龄Age在区间(0,149)范围内的外星人映射成人,执行结果如下,和预测结果一致。

    image

    配置

    初始化

    初始化是配置AutoMapper受人欢迎的模式,每个应用域应该配置一次:

    //初始化配置文件
    Mapper.Initialize(cfg =>
    {
        cfg.CreateMap<Aliens, Person>();
        cfg.AddProfile<AliensPersonProfile>();//添加一个配置文件
    });

    映射配置是静态的,此后不应该改变了。

    Profile实例

    可用来组织AutoMapper配置

    namespace ConditionalMapping
    {
        public class AliensPersonProfile : Profile
        {
            protected override void Configure()
            {
                //放一些CreateMap(...)等映射配置操作
    
            }
        }
    }

    自定义一个继承了Profile类的类,然后重写Configure方法,在该方法中放一些映射的配置。

    像下面这样初始化自定义的配置文件:

    //初始化配置文件
    Mapper.Initialize(cfg =>
    {
        cfg.AddProfile<AliensPersonProfile>();//添加一个配置文件
    });

    命名惯例

    可以设置源和目标的命名惯例。

    //初始化配置文件
    Mapper.Initialize(cfg =>
    {
        cfg.SourceMemberNamingConvention=new LowerUnderscoreNamingConvention();
        cfg.DestinationMemberNamingConvention=new PascalCaseNamingConvention();
    });

    也可以在配置文件中的Configure方法中设置:

    protected override void Configure()
    {
        SourceMemberNamingConvention = new LowerUnderscoreNamingConvention();
        DestinationMemberNamingConvention = new PascalCaseNamingConvention();
    }

    小试牛刀:

    在Aliens类中添加如下代码:

    public string MyName { set; get; }

    在Person类中添加如下代码:

    public string my_name { get; set; }

    结果如下,和预测结果一致:

    image

    可见,这种映射配置就是告诉AutoMapper这两种命名惯例可以相互映射。而且需要注意的是,这两句代码可放在CreateMap()方法之后。

    替换字符

    在成员名字映射期间,也可以替换个别的字符或者整个单词。

    配置Mapper(可在Initialize方法或配置文件中均可,后面不再提示),注意一定要在CreateMap方法之前,配置替换字符,否则没有效果。这也符合逻辑,只有先添加替换条件,才能按条件映射嘛。

    cfg.ReplaceMemberName("Ä", "A");
    cfg.ReplaceMemberName("í", "i");
    cfg.ReplaceMemberName("Tool", "Car");
    cfg.AddProfile<AliensPersonProfile>();

    小试牛刀:

    在Aliens类中添加如下代码:

    public int Ävíator { get; set; }
    public string ToolName { get; set; }

    在Person类中添加如下代码:

    public int Aviator { get; set; }
    public string CarName { get; set; }

    结果如下,和预测结果一致:

    image

    识别前缀/后缀

    有时候你的源类型和目标类型的属性有公共的前缀/后缀,由于这些命名不匹配的缘故,使你不得不处理这些自定义的成员映射。为了实现这个,可以识别前后缀:

    小试牛刀:

    在Aliens类中添加如下代码:

    public string PGender { get; set; }

    在Person类中添加如下代码:

    public string Gender { get; set; }

    可见,源类型中有一个前缀为“P”的字段PGender,要想成功映射为Person,就必须识别出前缀“P”,所以在Mapper的配置中添加代码(注意,添加到CreateMap方法之前,否则无效):

    cfg.RecognizePrefixes("P");

    结果如下,和预测结果一致:

    image

    默认情况下,AutoMapper识别前缀“Get”,如果你需要清除前缀:

    cfg.ClearPrefixes();

    全局属性/字段过滤

    默认情况下,AutoMapper映射每一个公共的属性/字段。你可以使用属性/字段过滤器过滤出不需要映射的属性/字段:

    //不映射任何字段
    cfg.ShouldMapField = fi => false;
    //只映射getter是private的属性
    cfg.ShouldMapProperty = pi => pi.GetMethod != null && pi.GetMethod.IsPrivate;
    cfg.AddProfile<AliensPersonProfile>();

    小试牛刀:

    分别给Aliens和Person类添加下面这段代码:

    private string code;
    public string Code
    {
        private get { return code; }
        set { code = value; }
    }

    Main方法中添加代码:

    var p10 = Mapper.Map<Person>(new Aliens() { Age = 44,Code = "111"});
    Console.WriteLine(string.Format("Person.Age={0},Person.code={1}",p10.Age,p10.code));//22,111

    结果和预测一样:

    image

    解释一下:

    我们在配置中添加了过滤器,只允许getter是private的属性映射,而Person的Age属性getter默认是public的,所以没有将我们给的值44映射到,因而返回默认的22,而Person的Code属性的getter是私有的,所以映射到了,但是要想取到映射后的值,我们只能通过公有的字段来获得。

    配置可见性

    默认情况下,AutoMapper只识别公有成员。虽然可以映射到私有的setter,但是如果整个属性是private/internal的,那么就会跳过internal/private的方法和属性。为了命令AutoMapper识别具有其他可见性的成员,重写默认的过滤器ShouldMapField或ShouldMapProperty:

    Mapper.Initialize(cfg =>
    {
        // 映射具有public或internal的getter的属性
        cfg.ShouldMapProperty = p => p.GetMethod.IsPublic || p.GetMethod.IsAssembly;
        cfg.CreateMap<Source, Destination>();
    });
  • 相关阅读:
    android实现 服务器功能
    jQuery部分源码帮助理解
    jquery 2.0.3代码结构
    Mac下配置JAVA_HOME
    用户环境变量
    你的apk有多不安全
    JadClipse eclipse反编译插件
    vim 使用笔记
    Makefile简易模板
    Linux watch 监控系统状态
  • 原文地址:https://www.cnblogs.com/farb/p/4934476.html
Copyright © 2011-2022 走看看