From c4365644f19892b04cda0f5a596fec20936440dc Mon Sep 17 00:00:00 2001 From: chaowlert Date: Fri, 26 May 2017 05:37:38 +0700 Subject: [PATCH] member side --- .../WhenMappingWithImplicitInheritance.cs | 10 ++- src/Mapster/Adapters/BaseClassAdapter.cs | 2 +- src/Mapster/Adapters/DictionaryAdapter.cs | 2 +- src/Mapster/Enums/MemberSide.cs | 14 ++++ src/Mapster/Mapster.csproj | 2 + src/Mapster/Models/ClassModel.cs | 2 +- src/Mapster/Models/FieldModel.cs | 2 +- src/Mapster/Models/IMemberModel.cs | 2 - src/Mapster/Models/IMemberModelEx.cs | 10 +++ src/Mapster/Models/KeyValuePairModel.cs | 4 +- src/Mapster/Models/MemberMapping.cs | 2 +- src/Mapster/Models/ParameterModel.cs | 2 +- src/Mapster/Models/PropertyModel.cs | 2 +- src/Mapster/Settings/ShouldMapMember.cs | 8 +-- .../Settings/ValueAccessingStrategy.cs | 2 +- src/Mapster/TypeAdapterConfig.cs | 20 +++--- src/Mapster/TypeAdapterSetter.cs | 72 +++++++++++++++---- src/Mapster/TypeAdapterSettings.cs | 4 +- src/Mapster/Utils/ReflectionUtils.cs | 12 ++-- 19 files changed, 124 insertions(+), 50 deletions(-) create mode 100644 src/Mapster/Enums/MemberSide.cs create mode 100644 src/Mapster/Models/IMemberModelEx.cs diff --git a/src/Mapster.Tests/WhenMappingWithImplicitInheritance.cs b/src/Mapster.Tests/WhenMappingWithImplicitInheritance.cs index a2846743..86d62d02 100644 --- a/src/Mapster.Tests/WhenMappingWithImplicitInheritance.cs +++ b/src/Mapster.Tests/WhenMappingWithImplicitInheritance.cs @@ -1,6 +1,7 @@ using System; using Microsoft.VisualStudio.TestTools.UnitTesting; using Shouldly; +using Mapster.Models; namespace Mapster.Tests { @@ -178,7 +179,8 @@ public void Derived_Config_Shares_Base_Config_Properties() //.MaxDepth(5) .Compile(); - var derivedConfig = TypeAdapterConfig.GlobalSettings.GetMergedSettings(typeof(DerivedPoco), typeof(SimpleDto), MapType.Map); + var tuple = new TypeTuple(typeof(DerivedPoco), typeof(SimpleDto)); + var derivedConfig = TypeAdapterConfig.GlobalSettings.GetMergedSettings(tuple, MapType.Map); derivedConfig.IgnoreNullValues.ShouldBe(true); derivedConfig.ShallowCopyForSameType.ShouldBe(true); @@ -195,7 +197,8 @@ public void Derived_Config_Shares_Base_Dest_Config_Properties() //.MaxDepth(5) .Compile(); - var derivedConfig = TypeAdapterConfig.GlobalSettings.GetMergedSettings(typeof(DerivedPoco), typeof(DerivedDto), MapType.Map); + var tuple = new TypeTuple(typeof(DerivedPoco), typeof(DerivedDto)); + var derivedConfig = TypeAdapterConfig.GlobalSettings.GetMergedSettings(tuple, MapType.Map); derivedConfig.IgnoreNullValues.ShouldBe(true); derivedConfig.ShallowCopyForSameType.ShouldBe(true); @@ -212,7 +215,8 @@ public void Derived_Config_Doesnt_Share_Base_Dest_Config_Properties_If_Disabled( //.MaxDepth(5) .Compile(); - var derivedConfig = TypeAdapterConfig.GlobalSettings.GetMergedSettings(typeof(DerivedPoco), typeof(DerivedDto), MapType.Map); + var tuple = new TypeTuple(typeof(DerivedPoco), typeof(DerivedDto)); + var derivedConfig = TypeAdapterConfig.GlobalSettings.GetMergedSettings(tuple, MapType.Map); derivedConfig.IgnoreNullValues.ShouldBeNull(); derivedConfig.ShallowCopyForSameType.ShouldBeNull(); diff --git a/src/Mapster/Adapters/BaseClassAdapter.cs b/src/Mapster/Adapters/BaseClassAdapter.cs index 4243c98c..2c39c4a1 100644 --- a/src/Mapster/Adapters/BaseClassAdapter.cs +++ b/src/Mapster/Adapters/BaseClassAdapter.cs @@ -78,7 +78,7 @@ protected static bool ProcessIgnores( out LambdaExpression condition) { condition = null; - if (!destinationMember.ShouldMapMember(config.ShouldMapMember)) + if (!destinationMember.ShouldMapMember(config.ShouldMapMember, MemberSide.Destination)) return true; return config.IgnoreIfs.TryGetValue(destinationMember.Name, out condition) diff --git a/src/Mapster/Adapters/DictionaryAdapter.cs b/src/Mapster/Adapters/DictionaryAdapter.cs index a025ed2d..add74d71 100644 --- a/src/Mapster/Adapters/DictionaryAdapter.cs +++ b/src/Mapster/Adapters/DictionaryAdapter.cs @@ -174,7 +174,7 @@ protected override ClassModel GetClassModel(Type destinationType, CompileArgumen .Where(name => name != null) .ToHashSet(); var propNames = arg.SourceType.GetFieldsAndProperties(accessorFlags: BindingFlags.NonPublic | BindingFlags.Public) - .Where(model => model.ShouldMapMember(arg.Settings.ShouldMapMember)) + .Where(model => model.ShouldMapMember(arg.Settings.ShouldMapMember, MemberSide.Source)) .Select(model => model.Name) .Where(name => !srcNames.Contains(name)) .Select(name => arg.Settings.NameMatchingStrategy.SourceMemberNameConverter(name)); diff --git a/src/Mapster/Enums/MemberSide.cs b/src/Mapster/Enums/MemberSide.cs new file mode 100644 index 00000000..1ec010d0 --- /dev/null +++ b/src/Mapster/Enums/MemberSide.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Mapster +{ + public enum MemberSide + { + Source, + Destination, + } +} diff --git a/src/Mapster/Mapster.csproj b/src/Mapster/Mapster.csproj index 51b89abf..b7c01c53 100644 --- a/src/Mapster/Mapster.csproj +++ b/src/Mapster/Mapster.csproj @@ -69,11 +69,13 @@ + + diff --git a/src/Mapster/Models/ClassModel.cs b/src/Mapster/Models/ClassModel.cs index 2c021285..5993b2a6 100644 --- a/src/Mapster/Models/ClassModel.cs +++ b/src/Mapster/Models/ClassModel.cs @@ -6,6 +6,6 @@ namespace Mapster.Models internal class ClassModel { public ConstructorInfo ConstructorInfo { get; set; } - public IEnumerable Members { get; set; } + public IEnumerable Members { get; set; } } } diff --git a/src/Mapster/Models/FieldModel.cs b/src/Mapster/Models/FieldModel.cs index 5b151dc8..5a3a8b7d 100644 --- a/src/Mapster/Models/FieldModel.cs +++ b/src/Mapster/Models/FieldModel.cs @@ -5,7 +5,7 @@ namespace Mapster.Models { - public class FieldModel : IMemberModel + public class FieldModel : IMemberModelEx { private readonly FieldInfo _fieldInfo; public FieldModel(FieldInfo fieldInfo) diff --git a/src/Mapster/Models/IMemberModel.cs b/src/Mapster/Models/IMemberModel.cs index d126d8c0..e2c4a0b9 100644 --- a/src/Mapster/Models/IMemberModel.cs +++ b/src/Mapster/Models/IMemberModel.cs @@ -12,8 +12,6 @@ public interface IMemberModel AccessModifier SetterModifier { get; } AccessModifier AccessModifier { get; } - Expression GetExpression(Expression source); - Expression SetExpression(Expression source, Expression value); IEnumerable GetCustomAttributes(bool inherit); } } diff --git a/src/Mapster/Models/IMemberModelEx.cs b/src/Mapster/Models/IMemberModelEx.cs new file mode 100644 index 00000000..98455f1f --- /dev/null +++ b/src/Mapster/Models/IMemberModelEx.cs @@ -0,0 +1,10 @@ +using System.Linq.Expressions; + +namespace Mapster.Models +{ + internal interface IMemberModelEx: IMemberModel + { + Expression GetExpression(Expression source); + Expression SetExpression(Expression source, Expression value); + } +} \ No newline at end of file diff --git a/src/Mapster/Models/KeyValuePairModel.cs b/src/Mapster/Models/KeyValuePairModel.cs index a61138b7..435b0ef4 100644 --- a/src/Mapster/Models/KeyValuePairModel.cs +++ b/src/Mapster/Models/KeyValuePairModel.cs @@ -7,11 +7,11 @@ namespace Mapster.Models { - public class KeyValuePairModel : IMemberModel + public class KeyValuePairModel : IMemberModelEx { readonly Func _getFn; readonly Func _setFn; - public KeyValuePairModel(string name, Type type, + public KeyValuePairModel(string name, Type type, Func getFn, Func setFn) { diff --git a/src/Mapster/Models/MemberMapping.cs b/src/Mapster/Models/MemberMapping.cs index 1af6ba0a..948173fd 100644 --- a/src/Mapster/Models/MemberMapping.cs +++ b/src/Mapster/Models/MemberMapping.cs @@ -5,7 +5,7 @@ namespace Mapster.Models internal class MemberMapping { public Expression Getter; - public IMemberModel DestinationMember; + public IMemberModelEx DestinationMember; public LambdaExpression SetterCondition; } } \ No newline at end of file diff --git a/src/Mapster/Models/ParameterModel.cs b/src/Mapster/Models/ParameterModel.cs index 4828921f..86f332f6 100644 --- a/src/Mapster/Models/ParameterModel.cs +++ b/src/Mapster/Models/ParameterModel.cs @@ -6,7 +6,7 @@ namespace Mapster.Models { - public class ParameterModel : IMemberModel + public class ParameterModel : IMemberModelEx { private readonly ParameterInfo _parameterInfo; public ParameterModel(ParameterInfo parameterInfo) diff --git a/src/Mapster/Models/PropertyModel.cs b/src/Mapster/Models/PropertyModel.cs index 421ca537..00d6ccbc 100644 --- a/src/Mapster/Models/PropertyModel.cs +++ b/src/Mapster/Models/PropertyModel.cs @@ -5,7 +5,7 @@ namespace Mapster.Models { - public class PropertyModel : IMemberModel + public class PropertyModel : IMemberModelEx { protected readonly PropertyInfo _propertyInfo; public PropertyModel(PropertyInfo propertyInfo) diff --git a/src/Mapster/Settings/ShouldMapMember.cs b/src/Mapster/Settings/ShouldMapMember.cs index 6b51ecdd..7df3f46d 100644 --- a/src/Mapster/Settings/ShouldMapMember.cs +++ b/src/Mapster/Settings/ShouldMapMember.cs @@ -5,9 +5,9 @@ namespace Mapster { public static class ShouldMapMember { - public static Func AllowNonPublic = model => model.AccessModifier != AccessModifier.None; - public static Func AllowPublic = model => model.AccessModifier == AccessModifier.Public ? (bool?)true : null; - public static Func IgnoreAdaptIgnore = model => model.HasCustomAttribute(typeof(AdaptIgnoreAttribute)) ? (bool?)false : null; - public static Func AllowAdaptMember = model => model.HasCustomAttribute(typeof(AdaptMemberAttribute)) ? (bool?)true : null; + public static Func AllowNonPublic = (model, _) => model.AccessModifier != AccessModifier.None; + public static Func AllowPublic = (model, _) => model.AccessModifier == AccessModifier.Public ? (bool?)true : null; + public static Func IgnoreAdaptIgnore = (model, _) => model.HasCustomAttribute(typeof(AdaptIgnoreAttribute)) ? (bool?)false : null; + public static Func AllowAdaptMember = (model, _) => model.HasCustomAttribute(typeof(AdaptMemberAttribute)) ? (bool?)true : null; } } diff --git a/src/Mapster/Settings/ValueAccessingStrategy.cs b/src/Mapster/Settings/ValueAccessingStrategy.cs index 5cf12260..673cff33 100644 --- a/src/Mapster/Settings/ValueAccessingStrategy.cs +++ b/src/Mapster/Settings/ValueAccessingStrategy.cs @@ -59,7 +59,7 @@ private static Expression PropertyOrFieldFn(Expression source, IMemberModel dest var strategy = arg.Settings.NameMatchingStrategy; var destinationMemberName = destinationMember.GetMemberName(arg.Settings.GetMemberNames, strategy.DestinationMemberNameConverter); return members - .Where(member => member.ShouldMapMember(arg.Settings.ShouldMapMember)) + .Where(member => member.ShouldMapMember(arg.Settings.ShouldMapMember, MemberSide.Source)) .Where(member => member.GetMemberName(arg.Settings.GetMemberNames, strategy.SourceMemberNameConverter) == destinationMemberName) .Select(member => member.GetExpression(source)) .FirstOrDefault(); diff --git a/src/Mapster/TypeAdapterConfig.cs b/src/Mapster/TypeAdapterConfig.cs index bba48a94..493036b8 100644 --- a/src/Mapster/TypeAdapterConfig.cs +++ b/src/Mapster/TypeAdapterConfig.cs @@ -297,7 +297,7 @@ internal LambdaExpression CreateMapExpression(TypeTuple tuple, MapType mapType) context.Running.Add(tuple); try { - var arg = GetCompileArgument(tuple.Source, tuple.Destination, mapType, context); + var arg = GetCompileArgument(tuple, mapType, context); return CreateMapExpression(arg); } finally @@ -365,7 +365,7 @@ internal LambdaExpression CreateInlineMapExpression(Type sourceType, Type destin context.Running.Add(tuple); try { - var arg = GetCompileArgument(tuple.Source, tuple.Destination, parentMapType == MapType.Projection ? MapType.Projection : MapType.InlineMap, context); + var arg = GetCompileArgument(tuple, parentMapType == MapType.Projection ? MapType.Projection : MapType.InlineMap, context); var exp = CreateMapExpression(arg); if (exp != null) { @@ -419,10 +419,10 @@ private LambdaExpression CreateMapToTargetInvokeExpression(Type sourceType, Type return Expression.Lambda(invoke, p1, p2); } - internal TypeAdapterSettings GetMergedSettings(Type sourceType, Type destinationType, MapType mapType) + internal TypeAdapterSettings GetMergedSettings(TypeTuple tuple, MapType mapType) { var settings = (from rule in this.Rules.Reverse() - let priority = rule.Priority(sourceType, destinationType, mapType) + let priority = rule.Priority(tuple.Source, tuple.Destination, mapType) where priority != null orderby priority.Value descending select rule.Settings).ToList(); @@ -434,19 +434,19 @@ orderby priority.Value descending //remove recursive include types if (mapType == MapType.MapToTarget) - result.Includes.Remove(new TypeTuple(sourceType, destinationType)); + result.Includes.Remove(tuple); else - result.Includes.RemoveAll(tuple => tuple.Source == sourceType); + result.Includes.RemoveAll(t => t.Source == tuple.Source); return result; } - CompileArgument GetCompileArgument(Type sourceType, Type destinationType, MapType mapType, CompileContext context) + CompileArgument GetCompileArgument(TypeTuple tuple, MapType mapType, CompileContext context) { - var setting = GetMergedSettings(sourceType, destinationType, mapType); + var setting = GetMergedSettings(tuple, mapType); var arg = new CompileArgument { - SourceType = sourceType, - DestinationType = destinationType, + SourceType = tuple.Source, + DestinationType = tuple.Destination, MapType = mapType, Context = context, Settings = setting, diff --git a/src/Mapster/TypeAdapterSetter.cs b/src/Mapster/TypeAdapterSetter.cs index a2a63080..1fb615bb 100644 --- a/src/Mapster/TypeAdapterSetter.cs +++ b/src/Mapster/TypeAdapterSetter.cs @@ -50,16 +50,35 @@ public static TSetter IgnoreAttribute(this TSetter setter, params Type[ foreach (var type in types) { - setter.Settings.ShouldMapMember.Add(member => member.HasCustomAttribute(type) ? (bool?)false : null); + setter.Settings.ShouldMapMember.Add((member, _) => member.HasCustomAttribute(type) ? (bool?)false : null); } return setter; } - public static TSetter ShouldMapMember(this TSetter setter, Func predicate, bool value) where TSetter : TypeAdapterSetter + public static TSetter IncludeAttribute(this TSetter setter, params Type[] types) where TSetter : TypeAdapterSetter { setter.CheckCompiled(); - setter.Settings.ShouldMapMember.Add(member => predicate(member) ? (bool?)value : null); + foreach (var type in types) + { + setter.Settings.ShouldMapMember.Add((member, _) => member.HasCustomAttribute(type) ? (bool?)true : null); + } + return setter; + } + + public static TSetter IgnoreMember(this TSetter setter, Func predicate) where TSetter : TypeAdapterSetter + { + setter.CheckCompiled(); + + setter.Settings.ShouldMapMember.Add((member, side) => predicate(member, side) ? (bool?)false : null); + return setter; + } + + public static TSetter IncludeMember(this TSetter setter, Func predicate) where TSetter : TypeAdapterSetter + { + setter.CheckCompiled(); + + setter.Settings.ShouldMapMember.Add((member, side) => predicate(member, side) ? (bool?)true : null); return setter; } @@ -116,7 +135,10 @@ public static TSetter Map( Invoker = invoker, Condition = null }); - setter.Settings.ShouldMapMember.Add(member => member.Name == memberName ? (bool?)true : null); + setter.Settings.ShouldMapMember.Add((member, side) => + (member.Name == memberName && side == MemberSide.Destination) + ? (bool?)true + : null); return setter; } @@ -134,7 +156,10 @@ public static TSetter Map( SourceMemberName = ReflectionUtils.GetMemberInfo(source, true)?.Member.Name, Condition = null }); - setter.Settings.ShouldMapMember.Add(member => member.Name == memberName ? (bool?)true : null); + setter.Settings.ShouldMapMember.Add((member, side) => + (member.Name == memberName && side == MemberSide.Destination) + ? (bool?)true + : null); return setter; } @@ -150,9 +175,24 @@ public static TSetter Map( SourceMemberName = sourceMemberName, Condition = null }); - setter.Settings.ShouldMapMember.Add(member => member.Name == destinationMemberName ? (bool?)true : null); if (sourceMemberName != destinationMemberName) - setter.Settings.ShouldMapMember.Add(member => member.Name == sourceMemberName ? (bool?)true : null); + { + setter.Settings.ShouldMapMember.Add((member, side) => + (member.Name == destinationMemberName && side == MemberSide.Destination) + ? (bool?)true + : null); + setter.Settings.ShouldMapMember.Add((member, side) => + (member.Name == sourceMemberName && side == MemberSide.Source) + ? (bool?)true + : null); + } + else + { + setter.Settings.ShouldMapMember.Add((member, _) => + member.Name == destinationMemberName + ? (bool?)true + : null); + } return setter; } @@ -163,13 +203,13 @@ public static TSetter EnableNonPublicMembers(this TSetter setter, bool if (value) { - setter.Settings.ShouldMapMember.Remove(Mapster.ShouldMapMember.AllowPublic); - setter.Settings.ShouldMapMember.Add(Mapster.ShouldMapMember.AllowNonPublic); + setter.Settings.ShouldMapMember.Remove(ShouldMapMember.AllowPublic); + setter.Settings.ShouldMapMember.Add(ShouldMapMember.AllowNonPublic); } else { - setter.Settings.ShouldMapMember.Remove(Mapster.ShouldMapMember.AllowNonPublic); - setter.Settings.ShouldMapMember.Add(Mapster.ShouldMapMember.AllowPublic); + setter.Settings.ShouldMapMember.Remove(ShouldMapMember.AllowNonPublic); + setter.Settings.ShouldMapMember.Add(ShouldMapMember.AllowPublic); } return setter; @@ -247,7 +287,10 @@ public TypeAdapterSetter Map( SourceMemberName = sourceMemberName, Condition = null }); - Settings.ShouldMapMember.Add(member => member.Name == sourceMemberName ? (bool?)true : null); + Settings.ShouldMapMember.Add((member, side) => + (member.Name == sourceMemberName && side == MemberSide.Source) + ? (bool?)true + : null); return this; } @@ -375,7 +418,10 @@ public TypeAdapterSetter Map( SourceMemberName = ReflectionUtils.GetMemberInfo(source, true)?.Member.Name, Condition = shouldMap }); - Settings.ShouldMapMember.Add(member => member.Name == memberName ? (bool?)true : null); + Settings.ShouldMapMember.Add((member, side) => + (member.Name == memberName && side == MemberSide.Destination) + ? (bool?)true + : null); return this; } diff --git a/src/Mapster/TypeAdapterSettings.cs b/src/Mapster/TypeAdapterSettings.cs index 6c6a1995..aef10c52 100644 --- a/src/Mapster/TypeAdapterSettings.cs +++ b/src/Mapster/TypeAdapterSettings.cs @@ -52,9 +52,9 @@ public bool? AvoidInlineMapping set => Set("AvoidInlineMapping", value); } - public List> ShouldMapMember + public List> ShouldMapMember { - get => Get("ShouldMapMember", () => new List>()); + get => Get("ShouldMapMember", () => new List>()); } public List> ValueAccessingStrategies { diff --git a/src/Mapster/Utils/ReflectionUtils.cs b/src/Mapster/Utils/ReflectionUtils.cs index 4e7ec2a9..2f890ffd 100644 --- a/src/Mapster/Utils/ReflectionUtils.cs +++ b/src/Mapster/Utils/ReflectionUtils.cs @@ -50,7 +50,7 @@ public static bool IsPoco(this Type type) return type.GetFieldsAndProperties(allowNoSetter: false).Any(); } - public static IEnumerable GetFieldsAndProperties(this Type type, bool allowNoSetter = true, BindingFlags accessorFlags = BindingFlags.Public) + public static IEnumerable GetFieldsAndProperties(this Type type, bool allowNoSetter = true, BindingFlags accessorFlags = BindingFlags.Public) { var bindingFlags = BindingFlags.Instance | accessorFlags; @@ -300,17 +300,17 @@ public static bool IsConvertible(this Type type) return typeof (IConvertible).GetTypeInfo().IsAssignableFrom(type.GetTypeInfo()); } - public static IMemberModel CreateModel(this PropertyInfo propertyInfo) + public static IMemberModelEx CreateModel(this PropertyInfo propertyInfo) { return new PropertyModel(propertyInfo); } - public static IMemberModel CreateModel(this FieldInfo propertyInfo) + public static IMemberModelEx CreateModel(this FieldInfo propertyInfo) { return new FieldModel(propertyInfo); } - public static IMemberModel CreateModel(this ParameterInfo propertyInfo) + public static IMemberModelEx CreateModel(this ParameterInfo propertyInfo) { return new ParameterModel(propertyInfo); } @@ -372,9 +372,9 @@ public static AccessModifier GetAccessModifier(this MethodBase methodBase) return AccessModifier.Private; } - public static bool ShouldMapMember(this IMemberModel member, IEnumerable> predicates) + public static bool ShouldMapMember(this IMemberModel member, IEnumerable> predicates, MemberSide side) { - return predicates.Select(predicate => predicate(member)) + return predicates.Select(predicate => predicate(member, side)) .FirstOrDefault(result => result != null) == true; }