当前位置 博文首页 > 初夏的阳光丶:AutoMapper源码解析

    初夏的阳光丶:AutoMapper源码解析

    作者:初夏的阳光丶 时间:2021-01-31 20:23

    在这里插入图片描述
    研究AutoMapper源码前,我们先来看一下AutoMapper的作用


    官网解释:AutoMapper是一个简单的小程序库,旨在解决看似复杂的问题-摆脱将一个对象映射到另一个对象的代码 解释

    首先一个简单的使用AutoMapper方法演示

    ar config = new MapperConfiguration(cfg => 
                    cfg.CreateMap<ModelObject, ModelDto>()
                );
                var mapper1 = config.CreateMapper();
                var mode;= mapper1.Map<ModelObject>(new ModelDto{ Name= 1 });
    
    

    构造函数

    在这段代码中默认创建MapperConfiguration对象,并且传入一个带有映射关系的Action
    当MapperConfiguration创建时,会默认执行构造函数

     public MapperConfiguration(MapperConfigurationExpression configurationExpression)
            {
                _mappers = configurationExpression.Mappers.ToArray();
                _resolvedMaps = new LockingConcurrentDictionary<TypePair, TypeMap>(GetTypeMap);
                _executionPlans = new LockingConcurrentDictionary<MapRequest, Delegate>(CompileExecutionPlan);
                _validator = new ConfigurationValidator(this, configurationExpression);
                ExpressionBuilder = new ExpressionBuilder(this);
    
                ServiceCtor = configurationExpression.ServiceCtor;
                EnableNullPropagationForQueryMapping = configurationExpression.EnableNullPropagationForQueryMapping ?? false;
                MaxExecutionPlanDepth = configurationExpression.Advanced.MaxExecutionPlanDepth + 1;
                ResultConverters = configurationExpression.Advanced.QueryableResultConverters.ToArray();
                Binders = configurationExpression.Advanced.QueryableBinders.ToArray();
                RecursiveQueriesMaxDepth = configurationExpression.Advanced.RecursiveQueriesMaxDepth;
    
                Configuration = new ProfileMap(configurationExpression);
                Profiles = new[] { Configuration }.Concat(configurationExpression.Profiles.Select(p => new ProfileMap(p, configurationExpression))).ToArray();
    
                configurationExpression.Features.Configure(this);
    
                foreach (var beforeSealAction in configurationExpression.Advanced.BeforeSealActions)
                    beforeSealAction?.Invoke(this);
                Seal();
            }
    

    在构造函数中实际就是将构建一个MapperConfigurationExpression表达式,然后将当前方法生成Action进行对象的映射,
    表达式创建完成之后就进入到AutoMapper核心方法Seal方法
    首先我们简单的看一下Seal方法

     private void Seal()
            {
                var derivedMaps = new List<Tuple<TypePair, TypeMap>>();
                var redirectedTypes = new List<Tuple<TypePair, TypePair>>();
    
                //获取所有的需要映射的集合 进行注册
                foreach (var profile in Profiles)
                {
                    //单个进行注册,传入当前对象
                    profile.Register(this);
                }
    
                //IncludeAllDerivedTypes 子类型
                foreach (var typeMap in _configuredMaps.Values.Where(tm => tm.IncludeAllDerivedTypes))
                {
                    //循环遍历获取可以赋值的派生类型
                    foreach (var derivedMap in _configuredMaps
                        .Where(tm =>
                            typeMap.SourceType.IsAssignableFrom(tm.Key.SourceType) &&
                            typeMap.DestinationType.IsAssignableFrom(tm.Key.DestinationType) &&
                            typeMap != tm.Value)
                        .Select(tm => tm.Value))
                    {
                        //获取派生类型
                        typeMap.IncludeDerivedTypes(derivedMap.SourceType, derivedMap.DestinationType);
                    }
                }
    
                foreach (var profile in Profiles)
                {
                    profile.Configure(this);
                }
    
                foreach (var typeMap in _configuredMaps.Values)
                {
                    _resolvedMaps[typeMap.Types] = typeMap;
    
                    if (typeMap.DestinationTypeOverride != null)
                    {
                        redirectedTypes.Add(Tuple.Create(typeMap.Types, new TypePair(typeMap.SourceType, typeMap.DestinationTypeOverride)));
                    }
                    derivedMaps.AddRange(GetDerivedTypeMaps(typeMap).Select(derivedMap => Tuple.Create(new TypePair(derivedMap.SourceType, typeMap.DestinationType), derivedMap)));
                }
                foreach (var redirectedType in redirectedTypes)
                {
                    var derivedMap = FindTypeMapFor(redirectedType.Item2);
                    if (derivedMap != null)
                    {
                        _resolvedMaps[redirectedType.Item1] = derivedMap;
                    }
                }
                foreach (var derivedMap in derivedMaps.Where(derivedMap => !_resolvedMaps.ContainsKey(derivedMap.Item1)))
                {
                    _resolvedMaps[derivedMap.Item1] = derivedMap.Item2;
                }
    
                foreach (var typeMap in _configuredMaps.Values)
                {
                    typeMap.Seal(this);
                }
    
                Features.Seal(this);
            }
    
    

    在这里首先会获取source Type和destination Type的字段映射对象,然后将实现过IProfiles的方法获取到,并且进行注册(添加Mapper关系)

    注册

     private void BuildTypeMap(IConfigurationProvider configurationProvider, ITypeMapConfiguration config)
            {
                //创建类型映射对象
                //config.SourceType 需要转化的实体
                //config.DestinationType 被映射的实体
                // config.IsReverseMap 是否需要反向映射实体
                var typeMap = TypeMapFactory.CreateTypeMap(config.SourceType, config.DestinationType, this, config.IsReverseMap);
    
                config.Configure(typeMap);
    
                configurationProvider.RegisterTypeMap(typeMap);
            }
    
    

    注册过程就是将需要被转化的实体和被映射的实体注册进TypeMap,最终添加MapperConfigurationExpression表达式中
    注册完成之后就是获取到所有的派生类型进行注册

    MapperConfigurationExpression表达式解析

    当所有的类都已经做好关系映射之后,就进入了 profile.Configure(this)方法,这个方法就是解析MapperConfigurationExpression表达式进行映射。在此之后会进去一些配置映射操作

    foreach (var typeMap in _configuredMaps.Values)
                {
                    typeMap.Seal(this);
                }
    
    public void Seal(IConfigurationProvider configurationProvider)
            {
                if(_sealed)
                {
                    return;
                }
                _sealed = true;
    
                _inheritedTypeMaps.ForAll(tm => _includedMembersTypeMaps.UnionWith(tm._includedMembersTypeMaps));
                foreach (var includedMemberTypeMap in _includedMembersTypeMaps)
                {
                    includedMemberTypeMap.TypeMap.Seal(configurationProvider);
                    ApplyIncludedMemberTypeMap(includedMemberTypeMap);
                }
                _inheritedTypeMaps.ForAll(tm => ApplyInheritedTypeMap(tm));
    
                _orderedPropertyMaps = PropertyMaps.OrderBy(map => map.MappingOrder).ToArray();
                _propertyMaps.Clear();
    
                MapExpression = CreateMapperLambda(configurationProvider, null);
    
                Features.Seal(configurationProvider);
            }
    
    

    在typeMap.Seal会调用CreateDestinationFunc方法创建一个lambda表达式,内容是new 一个destination对象,在CreateAssignmentFunc方法中会对派生类进行赋值的lambda内容,其中规则就是在注册是使用的规则,但是在两个对象做映射的过程中会有字段没有对应上的属性,CreateMapperFunc会产生一些规则,比如默认值赋值等等。生成的规则会存储在MapExpresion表达式中。

    总结

    在使用AutoMapper的过程中,系统只会运行一次seal()方法,存储好对象之间的关系,最终调用的时候只会在已经存储好的对象中去寻找映射关系,最终达成映射(ps:当大家在使用过程中,如果不想某些字段进行映射,可以使用IgnoreMapAttribute标记,在配置规则的过程中,如有发现有标记IgnoreMapAttribute的字段,会自动忽略)

    如有哪里讲得不是很明白或是有错误,欢迎指正
    如您喜欢的话不妨点个赞收藏一下吧

    bk