AutoMapper源碼解析


在這里插入圖片描述
研究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的字段,會自動忽略)

如有哪里講得不是很明白或是有錯誤,歡迎指正
如您喜歡的話不妨點個贊收藏一下吧


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM