diff --git a/src/Mapster.Tests/WhenConfiguringMapping.cs b/src/Mapster.Tests/WhenConfiguringMapping.cs index 809e6387..076e5679 100644 --- a/src/Mapster.Tests/WhenConfiguringMapping.cs +++ b/src/Mapster.Tests/WhenConfiguringMapping.cs @@ -142,9 +142,9 @@ public void NewInstanceConfigurationTest() obj.Name = "Tim"; obj.Child = new TestNewInstanceF() { Name = "Kıvanç" }; - TypeAdapterConfig + TypeAdapterConfig .NewConfig() - .ShallowCopyForSameType(true); + .ShallowCopyForSameType(true); var newObj2 = TypeAdapter.Adapt(obj); @@ -156,6 +156,28 @@ public void NewInstanceConfigurationTest() Assert.IsTrue(newObj2.Child.Name == "Antalya"); } + [TestMethod] + public void WhenDirectAssignmentForSameTypeConfigurate() + { + TestNewInstanceD obj = new TestNewInstanceD(); + obj.Name = "Tim"; + obj.Child = new TestNewInstanceF() { Name = "Kıvanç" }; + + var config = new TypeAdapterConfig(); + config.NewConfig() + .DirectAssignmentForSameType(true); + + var newObj2 = TypeAdapter.Adapt(obj, config); + + Assert.IsTrue(newObj2.Name == "Tim"); + Assert.IsTrue(obj.Child.Name == newObj2.Child.Name); + + obj.Child.Name = "Antalya"; + + Assert.IsTrue(newObj2.Child.Name == "Antalya"); + } + + #region Data private Source _source; diff --git a/src/Mapster/Adapters/BaseAdapter.cs b/src/Mapster/Adapters/BaseAdapter.cs index 4bdddd86..31d7541c 100644 --- a/src/Mapster/Adapters/BaseAdapter.cs +++ b/src/Mapster/Adapters/BaseAdapter.cs @@ -495,10 +495,14 @@ internal Expression CreateAdaptExpression(Expression source, Type destinationTyp if (_source.Type == destinationType && arg.MapType == MapType.Projection) return _source; + TypeAdapterRule? rule; + var tuple = new TypeTuple(_source.Type, destinationType); + arg.Context.Config.RuleMap.TryGetValue(tuple, out rule); + //adapt(_source); var notUsingDestinationValue = mapping is not { UseDestinationValue: true }; - var exp = _source.Type == destinationType && arg.Settings.ShallowCopyForSameType == true && notUsingDestinationValue && - !arg.Context.Config.HasRuleFor(_source.Type, destinationType) + var exp = _source.Type == destinationType && arg.Settings.ShallowCopyForSameType == true && notUsingDestinationValue + && rule == null ? _source : CreateAdaptExpressionCore(_source, destinationType, arg, mapping, destination); diff --git a/src/Mapster/Adapters/ClassAdapter.cs b/src/Mapster/Adapters/ClassAdapter.cs index 69af2101..042c0270 100644 --- a/src/Mapster/Adapters/ClassAdapter.cs +++ b/src/Mapster/Adapters/ClassAdapter.cs @@ -291,5 +291,18 @@ private static Expression SetValueByReflection(MemberMapping member, MemberExpre return Expression.MemberInit(newInstance, lines); } + + protected override Expression CreateExpressionBody(Expression source, Expression? destination, CompileArgument arg) + { + TypeAdapterRule? rule; + var tuple = new TypeTuple(source.Type, arg.DestinationType); + arg.Context.Config.RuleMap.TryGetValue(tuple, out rule); + + if (source.Type == arg.DestinationType && !arg.UseDestinationValue + && arg.Settings.DirectAssignmentForSameType.GetValueOrDefault() && arg.IsNotCustomConverterFactory(rule)) + return source; + + return base.CreateExpressionBody(source, destination, arg); + } } } diff --git a/src/Mapster/TypeAdapterSetter.cs b/src/Mapster/TypeAdapterSetter.cs index 834f4dbe..5dd0df11 100644 --- a/src/Mapster/TypeAdapterSetter.cs +++ b/src/Mapster/TypeAdapterSetter.cs @@ -108,6 +108,14 @@ public static TSetter ShallowCopyForSameType(this TSetter setter, bool return setter; } + public static TSetter DirectAssignmentForSameType(this TSetter setter, bool value) where TSetter : TypeAdapterSetter + { + setter.CheckCompiled(); + + setter.Settings.DirectAssignmentForSameType = value; + return setter; + } + public static TSetter EnumMappingStrategy(this TSetter setter, EnumMappingStrategy strategy) where TSetter : TypeAdapterSetter { setter.CheckCompiled(); diff --git a/src/Mapster/TypeAdapterSettings.cs b/src/Mapster/TypeAdapterSettings.cs index f94172a3..38e3a53c 100644 --- a/src/Mapster/TypeAdapterSettings.cs +++ b/src/Mapster/TypeAdapterSettings.cs @@ -39,11 +39,18 @@ public bool? PreserveReference get => Get(nameof(PreserveReference)); set => Set(nameof(PreserveReference), value); } + public bool? DirectAssignmentForSameType + { + get => Get(nameof(DirectAssignmentForSameType)); + set => Set(nameof(DirectAssignmentForSameType), value); + } + public bool? ShallowCopyForSameType { get => Get(nameof(ShallowCopyForSameType)); set => Set(nameof(ShallowCopyForSameType), value); } + public bool? IgnoreNullValues { get => Get(nameof(IgnoreNullValues)); diff --git a/src/Mapster/Utils/ReflectionUtils.cs b/src/Mapster/Utils/ReflectionUtils.cs index aa798fc1..81c3e21e 100644 --- a/src/Mapster/Utils/ReflectionUtils.cs +++ b/src/Mapster/Utils/ReflectionUtils.cs @@ -466,5 +466,18 @@ public static bool IsNotSelfCreation(this Type type) return type.GetFieldsAndProperties().All(it => (it.SetterModifier & (AccessModifier.Public | AccessModifier.NonPublic)) == 0); } + + public static bool IsNotCustomConverterFactory(this CompileArgument arg, TypeAdapterRule? rule) + { + if(rule != null) + { + if(arg.MapType == MapType.Map && rule.Settings.ConverterFactory != null) + return false; + if (arg.MapType == MapType.MapToTarget && rule.Settings.ConverterToTargetFactory != null) + return false; + } + + return true; + } } }