public static void ResolveDtoMaps(this IMapperConfigurationExpression mapper) { var types = GetAllDtos(); foreach (var type in types) { var dto = Activator.CreateInstance(type); var interfaces = type.GetInterfaces().Where(t2 => t2.IsGenericType && t2.GetGenericTypeDefinition() == typeof(IDto <,>)); foreach (var @interface in interfaces) { var genericBackArguments = @interface.GetGenericArguments(); var genericArguments = genericBackArguments.Reverse().ToArray(); if (genericArguments.Length < 2) { continue; } var createMaps = mapper.GetType().GetMethods().First(t => t.Name == "CreateMap" && t.IsGenericMethod); var map = createMaps.MakeGenericMethod(genericArguments).Invoke(mapper, null); var mapConfig = Activator.CreateInstance(typeof(Maps <,>).MakeGenericType(genericBackArguments), map); type.GetMethod(nameof(IDto <object, object> .MapExpandables)).Invoke(dto, new[] { mapConfig }); type.GetMethod(nameof(IDto <object, object> .Map)).Invoke(dto, new[] { mapConfig }); var mapBack = createMaps.MakeGenericMethod(genericBackArguments).Invoke(mapper, null); var mapBackConfig = Activator.CreateInstance(typeof(Maps <,>).MakeGenericType(genericArguments), mapBack); type.GetMethod(nameof(IDto <object, object> .MapBack)).Invoke(dto, new[] { mapBackConfig }); } } }
public static void CreateAutoAttributeMaps(this IMapperConfigurationExpression configuration, Type type, Type[] targetTypes, MemberList memberList) { //获取源中具有automapkeyattribute的所有属性 var sourceKeysPropertyInfo = type.GetProperties() .Where(w => w.GetCustomAttribute <AutoMapKeyAttribute>() != null) .Select(s => s).ToList(); foreach (var targetType in targetTypes) { if (!sourceKeysPropertyInfo.Any()) { configuration.CreateMap(type, targetType, memberList); continue; } BinaryExpression equalityComparer = null; //在lambda表达式中表示源示例:(source)=>… ParameterExpression sourceParameterExpression = Expression.Parameter(type, "source"); //在lambda表达式中表示目标示例:(target)=>… ParameterExpression targetParameterExpression = Expression.Parameter(targetType, "target"); //我们可以使用多个automapkey来比较 foreach (PropertyInfo propertyInfo in sourceKeysPropertyInfo) { //在lambda表达式中表示参数的特定属性示例:(source)=>source.id MemberExpression sourcePropertyExpression = Expression.Property(sourceParameterExpression, propertyInfo); //为目标查找与之比较的同名属性 //例如,如果我们在源代码中有属性id上的attribut automapkey,那么我们希望在目标中获取要比较的id,而不是 var targetPropertyInfo = targetType.GetProperty(sourcePropertyExpression.Member.Name); //如果目标中不存在automapkeyattribute为的属性,则会发生这种情况 if (targetPropertyInfo is null) { continue; } //在lambda表达式中,表示参数的特定属性示例:(target)=>target.id MemberExpression targetPropertyExpression = Expression.Property(targetParameterExpression, targetPropertyInfo); //比较源中automapkey定义的属性与目标中的属性不同 //示例(source,target)=>source.id==target.id BinaryExpression equal = Expression.Equal(sourcePropertyExpression, targetPropertyExpression); if (equalityComparer is null) { equalityComparer = equal; } else { //如果我们比较多个键,我们要在 //Exemple : (source, target) => source.Email == target.Email && source.UserName == target.UserName equalityComparer = Expression.And(equalityComparer, equal); } } //如果目标中没有匹配的automapkey //在这种情况下,我们添加默认映射 if (equalityComparer is null) { configuration.CreateMap(type, targetType, memberList); continue; } //我们需要使func<sourcetype,targettype,bool>的泛型类型来调用后面的expression.lambda var funcGenericType = typeof(Func <, ,>).MakeGenericType(type, targetType, typeof(bool)); //生成表达式的方法信息。lambda<func<sourceType,targetType,bool>>稍后调用 var lambdaMethodInfo = typeof(Expression).GetMethod("Lambda", 2, 1).MakeGenericMethod(funcGenericType); //调用expression.lambda var expressionLambdaResult = lambdaMethodInfo.Invoke(null, new object[] { equalityComparer, new ParameterExpression[] { sourceParameterExpression, targetParameterExpression } }); //获取imapperConfigurationExpression.createMap<source,target> var createMapMethodInfo = configuration.GetType().GetMethod("CreateMap", 1, 2).MakeGenericMethod(type, targetType); //调用configuration.createmap<source,target>()。 var createMapResult = createMapMethodInfo.Invoke(configuration, new object[] { memberList }); var autoMapperCollectionAssembly = Assembly.Load("AutoMapper.Collection"); var autoMapperCollectionTypes = autoMapperCollectionAssembly.GetTypes(); var equalityComparisonGenericMethodInfo = autoMapperCollectionTypes .Where(w => !w.IsGenericType && !w.IsNested) .SelectMany(s => s.GetMethods()).Where(w => w.Name == "EqualityComparison") .FirstOrDefault() .MakeGenericMethod(type, targetType); //调用EqualityComparison //Exemple configuration.CreateMap<Source, Target>().EqualityComparison((source, target) => source.Id == target.Id) equalityComparisonGenericMethodInfo.Invoke(createMapResult, new object[] { createMapResult, expressionLambdaResult }); } }
/// <summary> /// 创建映射 /// </summary> /// <param name="configuration"></param> /// <param name="type">原始类</param> /// <param name="targetTypes">目标类列表</param> /// <param name="memberList">成员类型,是Source还是Destination,用来验证字段已经全部映射完毕</param> public static void CreateAutoAttributeMaps(this IMapperConfigurationExpression configuration, Type type, Type[] targetTypes, MemberList memberList) { //Get all the properties in the source that have the AutoMapKeyAttribute var sourceKeysPropertyInfo = type.GetProperties() .Where(w => w.GetCustomAttribute <AutoMapKeyAttribute>() != null) .Select(s => s).ToList(); foreach (var targetType in targetTypes) { //这里表示,当前类打了自动映射的标签,且类里面的字段都没有打映射主键标签,那么当前类就直接进行映射 if (!sourceKeysPropertyInfo.Any()) { configuration.CreateMap(type, targetType, memberList); continue; } BinaryExpression equalityComparer = null; //In a lambda expression represent the source example : (source) => ... ParameterExpression sourceParameterExpression = Expression.Parameter(type, "source"); //In a lambda expression represent the target example : (target) => ... ParameterExpression targetParameterExpression = Expression.Parameter(targetType, "target"); //We could use multiple AutoMapKey to compare the determine equality //遍历那些打了自动映射键的字段,根据属性的键进行匹配,匹配上了的才进行赋值 foreach (PropertyInfo propertyInfo in sourceKeysPropertyInfo) { //In a lambda expression represent a specific property of a parameter example : (source) => source.Id MemberExpression sourcePropertyExpression = Expression.Property(sourceParameterExpression, propertyInfo); //Find the target a property with the same name to compare with //Example if we have in source the attribute AutoMapKey on the Property Id we want to get Id in the target to compare against var targetPropertyInfo = targetType.GetProperty(sourcePropertyExpression.Member.Name); //It happen if the property with AutoMapKeyAttribute does not exist in target if (targetPropertyInfo is null) { continue; } //In a lambda expression represent a specific property of a parameter example : (target) => target.Id MemberExpression targetPropertyExpression = Expression.Property(targetParameterExpression, targetPropertyInfo); //Compare the property defined by AutoMapKey in the source against the same property in the target //Example (source, target) => source.Id == target.Id BinaryExpression equal = Expression.Equal(sourcePropertyExpression, targetPropertyExpression); if (equalityComparer is null) { equalityComparer = equal; } else { //If we compare multiple key we want to make an and condition between //Example : (source, target) => source.Email == target.Email && source.UserName == target.UserName equalityComparer = Expression.And(equalityComparer, equal); } } //If there is not match for AutoMapKey in the target //In this case we add the default mapping if (equalityComparer is null) { configuration.CreateMap(type, targetType, memberList); continue; } //We need to make a generic type of Func<SourceType, TargetType, bool> to invoke later Expression.Lambda var funcGenericType = typeof(Func <, ,>).MakeGenericType(type, targetType, typeof(bool)); //Make a method info of Expression.Lambda<Func<SourceType, TargetType, bool>> to call later var lambdaMethodInfo = typeof(Expression).GetMethod("Lambda", 2, 1).MakeGenericMethod(funcGenericType); //Make the call to Expression.Lambda var expressionLambdaResult = lambdaMethodInfo.Invoke(null, new object[] { equalityComparer, new ParameterExpression[] { sourceParameterExpression, targetParameterExpression } }); //Get the method info of IMapperConfigurationExpression.CreateMap<Source, Target> var createMapMethodInfo = configuration.GetType().GetMethod("CreateMap", 1, 2).MakeGenericMethod(type, targetType); //Make the call to configuration.CreateMap<Source, Target>(). var createMapResult = createMapMethodInfo.Invoke(configuration, new object[] { memberList }); var autoMapperCollectionAssembly = Assembly.Load("AutoMapper.Collection"); var autoMapperCollectionTypes = autoMapperCollectionAssembly.GetTypes(); var equalityComparisonGenericMethodInfo = autoMapperCollectionTypes .Where(w => !w.IsGenericType && !w.IsNested) .SelectMany(s => s.GetMethods()).Where(w => w.Name == "EqualityComparison") .FirstOrDefault() .MakeGenericMethod(type, targetType); //Make the call to EqualityComparison //Exemple configuration.CreateMap<Source, Target>().EqualityComparison((source, target) => source.Id == target.Id) equalityComparisonGenericMethodInfo.Invoke(createMapResult, new object[] { createMapResult, expressionLambdaResult }); } }