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[redirect ad8 edType.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(configurationPr 139f ovider); }
在typeMap.Seal会调用CreateDestinationFunc方法创建一个lambda表达式,内容是new 一个destination对象,在CreateAssignmentFunc方法中会对派生类进行赋值的lambda内容,其中规则就是在注册是使用的规则,但是在两个对象做映射的过程中会有字段没有对应上的属性,CreateMapperFunc会产生一些规则,比如默认值赋值等等。生成的规则会存储在MapExpresion表达式中。
总结
在使用AutoMapper的过程中,系统只会运行一次seal()方法,存储好对象之间的关系,最终调用的时候只会在已经存储好的对象中去寻找映射关系,最终达成映射(ps:当大家在使用过程中,如果不想某些字段进行映射,可以使用IgnoreMapAttribute标记,在配置规则的过程中,如有发现有标记IgnoreMapAttribute的字段,会自动忽略)
如有哪里讲得不是很明白或是有错误,欢迎指正
如您喜欢的话不妨点个赞收藏一下吧
- Android异步消息处理机制完全解析,带你从源码的角度彻底理解
- ThreadPoolExecutor源码解析
- JFinal Handler源码解析——从配置到工作原理
- Retrofit2使用方式和源码解析
- sharding-jdbc源码解析之spring集成分片构造实现
- spring-web源码解析之MappingMediaTypeFileExtensionResolver
- OKHttp源码解析一(网络请求篇)
- Android事件分发机制完全解析,带你从源码的角度彻底理解(下)
- spring源码解析之默认配置文件名/WEB-INF/applicationContext.xml
- Android 网络框架之Retrofit2使用详解及从源码中解析原理
- 深入Java源码解析容器类List、Set、Map
- Spring源码解析之二 ------ 自定义标签的解析和注册(IOC的第一步)
- ReactiveCocoa v2.5 源码解析 之 架构总览
- tensorflow跑fashion mnist数据集全过程(利用Jupyter内含源码详细解析)
- JVM类加载机制(ClassLoader)源码解析(3)
- Android 插件化框架 DynamicLoadApk 源码解析
- Gson源码解析之InstanceCreator简单说明
- Android源码解析--SwipeMenuListView仿QQ聊天左滑
- 注册中心 Eureka 源码解析 —— 调试环境搭建
- 第36篇 Asp.Net源码解析(一)