From bc59684a601f3983d26bb7a3fcceeb09c5dfd6d5 Mon Sep 17 00:00:00 2001 From: DocSvartz Date: Fri, 12 Dec 2025 15:34:50 +0500 Subject: [PATCH 1/6] --Duplicate TypeAdapter.cs history into TypeAdapters/TypeAdapterToTarget.cs --- .../{TypeAdapter.cs => TypeAdapters/TypeAdapterToTarget.cs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/Mapster/{TypeAdapter.cs => TypeAdapters/TypeAdapterToTarget.cs} (100%) diff --git a/src/Mapster/TypeAdapter.cs b/src/Mapster/TypeAdapters/TypeAdapterToTarget.cs similarity index 100% rename from src/Mapster/TypeAdapter.cs rename to src/Mapster/TypeAdapters/TypeAdapterToTarget.cs From 2b09f5dbb5209ca7f7ab7d48f7ce5d5546fc9c3b Mon Sep 17 00:00:00 2001 From: DocSvartz Date: Fri, 12 Dec 2025 15:34:50 +0500 Subject: [PATCH 2/6] --Restore TypeAdapter.cs --- src/Mapster/TypeAdapter.cs | 309 +++++++++++++++++++++++++++++++++++++ 1 file changed, 309 insertions(+) create mode 100644 src/Mapster/TypeAdapter.cs diff --git a/src/Mapster/TypeAdapter.cs b/src/Mapster/TypeAdapter.cs new file mode 100644 index 00000000..7a42ab4a --- /dev/null +++ b/src/Mapster/TypeAdapter.cs @@ -0,0 +1,309 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Reflection; +using Mapster.Models; + +namespace Mapster +{ + public static class TypeAdapter + { + public static ITypeAdapterBuilder BuildAdapter(this TSource source) + { + return new TypeAdapterBuilder(source, TypeAdapterConfig.GlobalSettings); + } + + public static ITypeAdapterBuilder BuildAdapter(this TSource source, TypeAdapterConfig config) + { + return new TypeAdapterBuilder(source, config); + } + + /// + /// Adapt the source object to the destination type. + /// + /// Destination type. + /// Source object to adapt. + /// Adapted destination type. + [return: NotNullIfNotNull(nameof(source))] + public static TDestination? Adapt(this object? source) + { + return Adapt(source, TypeAdapterConfig.GlobalSettings); + } + + /// + /// Adapt the source object to the destination type. + /// + /// Destination type. + /// Source object to adapt. + /// Configuration + /// Adapted destination type. + [return: NotNullIfNotNull(nameof(source))] + public static TDestination? Adapt(this object? source, TypeAdapterConfig config) + { + // ReSharper disable once ConditionIsAlwaysTrueOrFalse + if (source == null) + return default; + var type = source.GetType(); + var fn = config.GetDynamicMapFunction(type); + return fn(source)!; + } + + /// + /// Adapt the source object to the destination type. + /// + /// Source type. + /// Destination type. + /// Source object to adapt. + /// Adapted destination type. + public static TDestination Adapt(this TSource source) + { + return TypeAdapter.Map(source); + } + + /// + /// Adapt the source object to the destination type. + /// + /// Source type. + /// Destination type. + /// Source object to adapt. + /// Configuration + /// Adapted destination type. + public static TDestination Adapt(this TSource source, TypeAdapterConfig config) + { + var fn = config.GetMapFunction(); + return fn(source); + } + + /// + /// Adapt the source object to the existing destination object. + /// + /// Source type. + /// Destination type. + /// Source object to adapt. + /// The destination object to populate. + /// Adapted destination type. + public static TDestination Adapt(this TSource source, TDestination destination) + { + return Adapt(source, destination, TypeAdapterConfig.GlobalSettings); + } + + /// + /// Adapt the source object to the existing destination object. + /// + /// Source type. + /// Destination type. + /// Source object to adapt. + /// The destination object to populate. + /// Configuration + /// Adapted destination type. + public static TDestination Adapt(this TSource source, TDestination destination, TypeAdapterConfig config) + { + var sourceType = source?.GetType(); + var destinationType = destination?.GetType(); + + if (sourceType == typeof(object)) // Infinity loop in ObjectAdapter if Runtime Type of source is Object + return destination; + + if (typeof(TSource) == typeof(object) || typeof(TDestination) == typeof(object)) + return UpdateFuncFromPackedinObject(source, destination, config, sourceType, destinationType); + + var fn = config.GetMapToTargetFunction(); + return fn(source, destination); + } + + private static TDestination UpdateFuncFromPackedinObject(TSource source, TDestination destination, TypeAdapterConfig config, Type sourceType, Type destinationType) + { + dynamic del = config.GetMapToTargetFunction(sourceType, destinationType); + + + if (sourceType.GetTypeInfo().IsVisible && destinationType.GetTypeInfo().IsVisible) + { + dynamic objfn = del; + return objfn((dynamic)source, (dynamic)destination); + } + else + { + //NOTE: if type is non-public, we cannot use dynamic + //DynamicInvoke is slow, but works with non-public + return (TDestination)del.DynamicInvoke(source, destination); + } + } + + /// + /// Adapt the source object to the destination type. + /// + /// Source object to adapt. + /// The type of the source object. + /// The type of the destination object. + /// Adapted destination type. + public static object? Adapt(this object source, Type sourceType, Type destinationType) + { + if (source != null && + sourceType.IsOpenGenericType() && destinationType.IsOpenGenericType()) + { + var arg = source.GetType().GetGenericArguments(); + return Adapt(source, sourceType.MakeGenericType(arg), destinationType.MakeGenericType(arg), TypeAdapterConfig.GlobalSettings); + } + return Adapt(source, sourceType, destinationType, TypeAdapterConfig.GlobalSettings); + } + + /// + /// Adapt the source object to the destination type. + /// + /// Source object to adapt. + /// The type of the source object. + /// The type of the destination object. + /// Configuration + /// Adapted destination type. + public static object? Adapt(this object source, Type sourceType, Type destinationType, TypeAdapterConfig config) + { + var del = config.GetMapFunction(sourceType, destinationType); + if (sourceType.GetTypeInfo().IsVisible && destinationType.GetTypeInfo().IsVisible) + { + dynamic fn = del; + return fn((dynamic)source); + } + else + { + //NOTE: if type is non-public, we cannot use dynamic + //DynamicInvoke is slow, but works with non-public + return del.DynamicInvoke(source); + } + } + + /// + /// Adapt the source object to an existing destination object. + /// + /// Source object to adapt. + /// Destination object to populate. + /// The type of the source object. + /// The type of the destination object. + /// Adapted destination type. + public static object? Adapt(this object source, object destination, Type sourceType, Type destinationType) + { + return Adapt(source, destination, sourceType, destinationType, TypeAdapterConfig.GlobalSettings); + } + + /// + /// Adapt the source object to an existing destination object. + /// + /// Source object to adapt. + /// Destination object to populate. + /// The type of the source object. + /// The type of the destination object. + /// Configuration + /// Adapted destination type. + public static object? Adapt(this object source, object destination, Type sourceType, Type destinationType, TypeAdapterConfig config) + { + var del = config.GetMapToTargetFunction(sourceType, destinationType); + if (sourceType.GetTypeInfo().IsVisible && destinationType.GetTypeInfo().IsVisible) + { + dynamic fn = del; + return fn((dynamic)source, (dynamic)destination); + } + else + { + //NOTE: if type is non-public, we cannot use dynamic + //DynamicInvoke is slow, but works with non-public + return del.DynamicInvoke(source, destination); + } + } + + /// + /// Validate properties and Adapt the source object to the destination type. + /// + /// Source type. + /// Destination type. + /// Source object to adapt. + /// Adapted destination type. + public static TDestination ValidateAndAdapt(this TSource source) + { + var sourceType = typeof(TSource); + var selectorType = typeof(TDestination); + + var sourceProperties = new HashSet(sourceType.GetProperties().Select(p => p.Name)); + var selectorProperties = new HashSet(selectorType.GetProperties().Select(p=> p.Name)); + + foreach (var selectorProperty in selectorProperties) + { + if (sourceProperties.Contains(selectorProperty)) continue; + throw new Exception($"Property {selectorProperty} does not exist in {sourceType.Name} and is not configured in Mapster"); + } + return source.Adapt(); + } + + /// + /// Validate properties with configuration and Adapt the source object to the destination type. + /// + /// Source type. + /// Destination type. + /// Source object to adapt. + /// Configuration + /// Adapted destination type. + public static TDestination ValidateAndAdapt(this TSource source, TypeAdapterConfig config) + { + var sourceType = typeof(TSource); + var selectorType = typeof(TDestination); + + var sourceProperties = new HashSet(sourceType.GetProperties().Select(p => p.Name)); + var selectorProperties = new HashSet(selectorType.GetProperties().Select(p=> p.Name)); + + // Get the rule map for the current types + var ruleMap = config.RuleMap; + var typeTuple = new TypeTuple(sourceType, selectorType); + ruleMap.TryGetValue(typeTuple, out var rule); + + foreach (var selectorProperty in selectorProperties) + { + if (sourceProperties.Contains(selectorProperty)) continue; + // Check whether the adapter config has a config for the property + if (rule != null && rule.Settings.Resolvers.Any(r => r.DestinationMemberName.Equals(selectorProperty))) continue; + throw new Exception($"Property {selectorProperty} does not exist in {sourceType.Name} and is not configured in Mapster"); + } + return source.Adapt(config); + } + + + /// + /// Adapt the source object to a destination type using a temporary configuration. + /// A new TypeAdapterConfig is created for this call, ensuring GlobalSettings remain unchanged. + /// Safe for init-only properties and record types. + /// + /// Destination type. + /// Source object to adapt. + /// Action to customize the temporary config. + /// Adapted destination object of type TDestination. + public static TDestination Adapt(this object? source, Action configAction) + { + var config = TypeAdapterConfig.GlobalSettings.Clone(); + configAction(config); + return source.Adapt(config); + } + + /// + /// Adapt the source object from TSource to TDestination using a dedicated TypeAdapterSetter. + /// A temporary TypeAdapterConfig is created and configured via the setter. + /// Safe for init-only properties and record types, without modifying GlobalSettings. + /// + /// Source type. + /// Destination type. + /// Source object to adapt. + /// Action to customize the TypeAdapterSetter. + /// Adapted destination object of type TDestination. + public static TDestination Adapt(this object? source, Action> configAction) + { + var config = TypeAdapterConfig.GlobalSettings.Clone(); + var setter = config.ForType(); + configAction(setter); + setter.Settings.Resolvers.Reverse(); + return source.Adapt(config); + } + } + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Minor Code Smell", "S1104:Fields should not have public accessibility", Justification = "")] + public static class TypeAdapter + { + public static Func Map = TypeAdapterConfig.GlobalSettings.GetMapFunction(); + } +} From e6f3abfa03cfa08c67b95f101dce117a40b1df8d Mon Sep 17 00:00:00 2001 From: DocSvartz Date: Fri, 12 Dec 2025 15:41:22 +0500 Subject: [PATCH 3/6] Extracting MaptoTarget adapters to a file TypeAdapterToTarget.cs --- src/Mapster/Mapster.csproj | 3 + src/Mapster/TypeAdapter.cs | 97 +------- .../TypeAdapters/TypeAdapterToTarget.cs | 213 +----------------- 3 files changed, 8 insertions(+), 305 deletions(-) diff --git a/src/Mapster/Mapster.csproj b/src/Mapster/Mapster.csproj index f8299fd2..b3f66b00 100644 --- a/src/Mapster/Mapster.csproj +++ b/src/Mapster/Mapster.csproj @@ -29,4 +29,7 @@ + + + \ No newline at end of file diff --git a/src/Mapster/TypeAdapter.cs b/src/Mapster/TypeAdapter.cs index 7a42ab4a..ec1b1a6e 100644 --- a/src/Mapster/TypeAdapter.cs +++ b/src/Mapster/TypeAdapter.cs @@ -7,7 +7,7 @@ namespace Mapster { - public static class TypeAdapter + public static partial class TypeAdapter { public static ITypeAdapterBuilder BuildAdapter(this TSource source) { @@ -75,61 +75,6 @@ public static TDestination Adapt(this TSource source, Typ return fn(source); } - /// - /// Adapt the source object to the existing destination object. - /// - /// Source type. - /// Destination type. - /// Source object to adapt. - /// The destination object to populate. - /// Adapted destination type. - public static TDestination Adapt(this TSource source, TDestination destination) - { - return Adapt(source, destination, TypeAdapterConfig.GlobalSettings); - } - - /// - /// Adapt the source object to the existing destination object. - /// - /// Source type. - /// Destination type. - /// Source object to adapt. - /// The destination object to populate. - /// Configuration - /// Adapted destination type. - public static TDestination Adapt(this TSource source, TDestination destination, TypeAdapterConfig config) - { - var sourceType = source?.GetType(); - var destinationType = destination?.GetType(); - - if (sourceType == typeof(object)) // Infinity loop in ObjectAdapter if Runtime Type of source is Object - return destination; - - if (typeof(TSource) == typeof(object) || typeof(TDestination) == typeof(object)) - return UpdateFuncFromPackedinObject(source, destination, config, sourceType, destinationType); - - var fn = config.GetMapToTargetFunction(); - return fn(source, destination); - } - - private static TDestination UpdateFuncFromPackedinObject(TSource source, TDestination destination, TypeAdapterConfig config, Type sourceType, Type destinationType) - { - dynamic del = config.GetMapToTargetFunction(sourceType, destinationType); - - - if (sourceType.GetTypeInfo().IsVisible && destinationType.GetTypeInfo().IsVisible) - { - dynamic objfn = del; - return objfn((dynamic)source, (dynamic)destination); - } - else - { - //NOTE: if type is non-public, we cannot use dynamic - //DynamicInvoke is slow, but works with non-public - return (TDestination)del.DynamicInvoke(source, destination); - } - } - /// /// Adapt the source object to the destination type. /// @@ -170,45 +115,7 @@ private static TDestination UpdateFuncFromPackedinObject( //DynamicInvoke is slow, but works with non-public return del.DynamicInvoke(source); } - } - - /// - /// Adapt the source object to an existing destination object. - /// - /// Source object to adapt. - /// Destination object to populate. - /// The type of the source object. - /// The type of the destination object. - /// Adapted destination type. - public static object? Adapt(this object source, object destination, Type sourceType, Type destinationType) - { - return Adapt(source, destination, sourceType, destinationType, TypeAdapterConfig.GlobalSettings); - } - - /// - /// Adapt the source object to an existing destination object. - /// - /// Source object to adapt. - /// Destination object to populate. - /// The type of the source object. - /// The type of the destination object. - /// Configuration - /// Adapted destination type. - public static object? Adapt(this object source, object destination, Type sourceType, Type destinationType, TypeAdapterConfig config) - { - var del = config.GetMapToTargetFunction(sourceType, destinationType); - if (sourceType.GetTypeInfo().IsVisible && destinationType.GetTypeInfo().IsVisible) - { - dynamic fn = del; - return fn((dynamic)source, (dynamic)destination); - } - else - { - //NOTE: if type is non-public, we cannot use dynamic - //DynamicInvoke is slow, but works with non-public - return del.DynamicInvoke(source, destination); - } - } + } /// /// Validate properties and Adapt the source object to the destination type. diff --git a/src/Mapster/TypeAdapters/TypeAdapterToTarget.cs b/src/Mapster/TypeAdapters/TypeAdapterToTarget.cs index 7a42ab4a..0e82e3d5 100644 --- a/src/Mapster/TypeAdapters/TypeAdapterToTarget.cs +++ b/src/Mapster/TypeAdapters/TypeAdapterToTarget.cs @@ -1,80 +1,10 @@ using System; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Linq; using System.Reflection; -using Mapster.Models; namespace Mapster { - public static class TypeAdapter + public static partial class TypeAdapter { - public static ITypeAdapterBuilder BuildAdapter(this TSource source) - { - return new TypeAdapterBuilder(source, TypeAdapterConfig.GlobalSettings); - } - - public static ITypeAdapterBuilder BuildAdapter(this TSource source, TypeAdapterConfig config) - { - return new TypeAdapterBuilder(source, config); - } - - /// - /// Adapt the source object to the destination type. - /// - /// Destination type. - /// Source object to adapt. - /// Adapted destination type. - [return: NotNullIfNotNull(nameof(source))] - public static TDestination? Adapt(this object? source) - { - return Adapt(source, TypeAdapterConfig.GlobalSettings); - } - - /// - /// Adapt the source object to the destination type. - /// - /// Destination type. - /// Source object to adapt. - /// Configuration - /// Adapted destination type. - [return: NotNullIfNotNull(nameof(source))] - public static TDestination? Adapt(this object? source, TypeAdapterConfig config) - { - // ReSharper disable once ConditionIsAlwaysTrueOrFalse - if (source == null) - return default; - var type = source.GetType(); - var fn = config.GetDynamicMapFunction(type); - return fn(source)!; - } - - /// - /// Adapt the source object to the destination type. - /// - /// Source type. - /// Destination type. - /// Source object to adapt. - /// Adapted destination type. - public static TDestination Adapt(this TSource source) - { - return TypeAdapter.Map(source); - } - - /// - /// Adapt the source object to the destination type. - /// - /// Source type. - /// Destination type. - /// Source object to adapt. - /// Configuration - /// Adapted destination type. - public static TDestination Adapt(this TSource source, TypeAdapterConfig config) - { - var fn = config.GetMapFunction(); - return fn(source); - } - /// /// Adapt the source object to the existing destination object. /// @@ -105,9 +35,9 @@ public static TDestination Adapt(this TSource source, TDe if (sourceType == typeof(object)) // Infinity loop in ObjectAdapter if Runtime Type of source is Object return destination; - if (typeof(TSource) == typeof(object) || typeof(TDestination) == typeof(object)) + if (typeof(TSource) == typeof(object) || typeof(TDestination) == typeof(object)) return UpdateFuncFromPackedinObject(source, destination, config, sourceType, destinationType); - + var fn = config.GetMapToTargetFunction(); return fn(source, destination); } @@ -130,48 +60,6 @@ private static TDestination UpdateFuncFromPackedinObject( } } - /// - /// Adapt the source object to the destination type. - /// - /// Source object to adapt. - /// The type of the source object. - /// The type of the destination object. - /// Adapted destination type. - public static object? Adapt(this object source, Type sourceType, Type destinationType) - { - if (source != null && - sourceType.IsOpenGenericType() && destinationType.IsOpenGenericType()) - { - var arg = source.GetType().GetGenericArguments(); - return Adapt(source, sourceType.MakeGenericType(arg), destinationType.MakeGenericType(arg), TypeAdapterConfig.GlobalSettings); - } - return Adapt(source, sourceType, destinationType, TypeAdapterConfig.GlobalSettings); - } - - /// - /// Adapt the source object to the destination type. - /// - /// Source object to adapt. - /// The type of the source object. - /// The type of the destination object. - /// Configuration - /// Adapted destination type. - public static object? Adapt(this object source, Type sourceType, Type destinationType, TypeAdapterConfig config) - { - var del = config.GetMapFunction(sourceType, destinationType); - if (sourceType.GetTypeInfo().IsVisible && destinationType.GetTypeInfo().IsVisible) - { - dynamic fn = del; - return fn((dynamic)source); - } - else - { - //NOTE: if type is non-public, we cannot use dynamic - //DynamicInvoke is slow, but works with non-public - return del.DynamicInvoke(source); - } - } - /// /// Adapt the source object to an existing destination object. /// @@ -209,101 +97,6 @@ private static TDestination UpdateFuncFromPackedinObject( return del.DynamicInvoke(source, destination); } } - - /// - /// Validate properties and Adapt the source object to the destination type. - /// - /// Source type. - /// Destination type. - /// Source object to adapt. - /// Adapted destination type. - public static TDestination ValidateAndAdapt(this TSource source) - { - var sourceType = typeof(TSource); - var selectorType = typeof(TDestination); - - var sourceProperties = new HashSet(sourceType.GetProperties().Select(p => p.Name)); - var selectorProperties = new HashSet(selectorType.GetProperties().Select(p=> p.Name)); - - foreach (var selectorProperty in selectorProperties) - { - if (sourceProperties.Contains(selectorProperty)) continue; - throw new Exception($"Property {selectorProperty} does not exist in {sourceType.Name} and is not configured in Mapster"); - } - return source.Adapt(); - } - - /// - /// Validate properties with configuration and Adapt the source object to the destination type. - /// - /// Source type. - /// Destination type. - /// Source object to adapt. - /// Configuration - /// Adapted destination type. - public static TDestination ValidateAndAdapt(this TSource source, TypeAdapterConfig config) - { - var sourceType = typeof(TSource); - var selectorType = typeof(TDestination); - - var sourceProperties = new HashSet(sourceType.GetProperties().Select(p => p.Name)); - var selectorProperties = new HashSet(selectorType.GetProperties().Select(p=> p.Name)); - - // Get the rule map for the current types - var ruleMap = config.RuleMap; - var typeTuple = new TypeTuple(sourceType, selectorType); - ruleMap.TryGetValue(typeTuple, out var rule); - - foreach (var selectorProperty in selectorProperties) - { - if (sourceProperties.Contains(selectorProperty)) continue; - // Check whether the adapter config has a config for the property - if (rule != null && rule.Settings.Resolvers.Any(r => r.DestinationMemberName.Equals(selectorProperty))) continue; - throw new Exception($"Property {selectorProperty} does not exist in {sourceType.Name} and is not configured in Mapster"); - } - return source.Adapt(config); - } - - /// - /// Adapt the source object to a destination type using a temporary configuration. - /// A new TypeAdapterConfig is created for this call, ensuring GlobalSettings remain unchanged. - /// Safe for init-only properties and record types. - /// - /// Destination type. - /// Source object to adapt. - /// Action to customize the temporary config. - /// Adapted destination object of type TDestination. - public static TDestination Adapt(this object? source, Action configAction) - { - var config = TypeAdapterConfig.GlobalSettings.Clone(); - configAction(config); - return source.Adapt(config); - } - - /// - /// Adapt the source object from TSource to TDestination using a dedicated TypeAdapterSetter. - /// A temporary TypeAdapterConfig is created and configured via the setter. - /// Safe for init-only properties and record types, without modifying GlobalSettings. - /// - /// Source type. - /// Destination type. - /// Source object to adapt. - /// Action to customize the TypeAdapterSetter. - /// Adapted destination object of type TDestination. - public static TDestination Adapt(this object? source, Action> configAction) - { - var config = TypeAdapterConfig.GlobalSettings.Clone(); - var setter = config.ForType(); - configAction(setter); - setter.Settings.Resolvers.Reverse(); - return source.Adapt(config); - } - } - - [System.Diagnostics.CodeAnalysis.SuppressMessage("Minor Code Smell", "S1104:Fields should not have public accessibility", Justification = "")] - public static class TypeAdapter - { - public static Func Map = TypeAdapterConfig.GlobalSettings.GetMapFunction(); } } From 105336652b88c759a28a8d2e8afa33f424479282 Mon Sep 17 00:00:00 2001 From: DocSvartz Date: Fri, 12 Dec 2025 16:28:02 +0500 Subject: [PATCH 4/6] add MapToTargetAdapt and fix tests --- src/Mapster.Tests/WhenForkingConfig.cs | 2 +- src/Mapster.Tests/WhenIgnoreMapping.cs | 2 +- .../WhenMappingIgnoreNullValues.cs | 2 +- src/Mapster.Tests/WhenMappingInitProperty.cs | 4 +- .../WhenMappingNullableEnumRegression.cs | 2 +- .../WhenMappingObjectRegression.cs | 14 +-- ...MappingPrimitiveCustomMappingRegression.cs | 4 +- .../WhenMappingRecordRegression.cs | 50 +++++------ .../WhenMappingStructRegression.cs | 4 +- .../WhenMappingWithAdaptIgnoreRegression.cs | 2 +- .../WhenMappingWithSecondSourceObject.cs | 2 +- .../WhenPerformingAfterMapping.cs | 2 +- .../WhenPerformingBeforeMapping.cs | 2 +- .../TypeAdapters/TypeAdapterToTarget.cs | 87 +++++++++++-------- 14 files changed, 97 insertions(+), 82 deletions(-) diff --git a/src/Mapster.Tests/WhenForkingConfig.cs b/src/Mapster.Tests/WhenForkingConfig.cs index 84b37d37..2b33c23b 100644 --- a/src/Mapster.Tests/WhenForkingConfig.cs +++ b/src/Mapster.Tests/WhenForkingConfig.cs @@ -65,7 +65,7 @@ public void Fork_Setting() dto.Name1.ShouldBe(poco.Name1); dto.Name2.ShouldBe("Bar"); - var str = poco.Name2.Adapt(dto.Name2, config); + var str = poco.Name2.MapToTargetAdapt(dto.Name2, config); str.ShouldBe(poco.Name2); } diff --git a/src/Mapster.Tests/WhenIgnoreMapping.cs b/src/Mapster.Tests/WhenIgnoreMapping.cs index 245c4e63..233b76f4 100644 --- a/src/Mapster.Tests/WhenIgnoreMapping.cs +++ b/src/Mapster.Tests/WhenIgnoreMapping.cs @@ -83,7 +83,7 @@ public void WhenClassIgnoreCtorParamGetDefaultValue() var dest = new B707(123, "Hello"); var docKind = source.Adapt(config); - var mapTotarget = source.Adapt(dest,config); + var mapTotarget = source.MapToTargetAdapt(dest,config); docKind.Id.ShouldBe(0); mapTotarget.Id.ShouldBe(123); diff --git a/src/Mapster.Tests/WhenMappingIgnoreNullValues.cs b/src/Mapster.Tests/WhenMappingIgnoreNullValues.cs index e98dffb7..ab7d7bf4 100644 --- a/src/Mapster.Tests/WhenMappingIgnoreNullValues.cs +++ b/src/Mapster.Tests/WhenMappingIgnoreNullValues.cs @@ -31,7 +31,7 @@ public void Map_To_Target() .Compile(); var source = new SourceClass(); - var dest = source.Adapt(new DestClass()); + var dest = source.MapToTargetAdapt(new DestClass()); Assert.AreEqual("Hello", dest.Title); Assert.IsNotNull(dest.Sub); diff --git a/src/Mapster.Tests/WhenMappingInitProperty.cs b/src/Mapster.Tests/WhenMappingInitProperty.cs index 6c1352de..f1ec62ee 100644 --- a/src/Mapster.Tests/WhenMappingInitProperty.cs +++ b/src/Mapster.Tests/WhenMappingInitProperty.cs @@ -17,7 +17,7 @@ public void WhenMappingToHiddenandNewInitFieldDestination() { var source = new Source672() { Id = 156}; var c = source.Adapt(); - var s = source.Adapt(new BDestination()); + var s = source.MapToTargetAdapt(new BDestination()); ((ADestination)c).Id.ShouldBe(default); // Hidden Base member is not mapping s.Id.ShouldBe(156); @@ -31,7 +31,7 @@ public void WhenMappingToHiddenandNewInitFieldWithConstructUsing() var source = new Source672() { Id = 256 }; var c = source.Adapt(); - var s = source.Adapt(new BDestination()); + var s = source.MapToTargetAdapt(new BDestination()); ((ADestination)c).Id.ShouldBe(default); // Hidden Base member is not mapping s.Id.ShouldBe(256); diff --git a/src/Mapster.Tests/WhenMappingNullableEnumRegression.cs b/src/Mapster.Tests/WhenMappingNullableEnumRegression.cs index c6b4281e..d6e1c49f 100644 --- a/src/Mapster.Tests/WhenMappingNullableEnumRegression.cs +++ b/src/Mapster.Tests/WhenMappingNullableEnumRegression.cs @@ -47,7 +47,7 @@ public void UpdateNullEnumToClass() var mDest2 = new MyDestination() { TypeEmployer = new KeyValueData("Admin", null) }; var _MyDestination = myClass?.Adapt(); // Work - var _result = _MyDestination.Adapt(mDest2); + var _result = _MyDestination.MapToTargetAdapt(mDest2); _result.TypeEmployer.Key.ShouldBe(MyEnum.User.ToString()); } diff --git a/src/Mapster.Tests/WhenMappingObjectRegression.cs b/src/Mapster.Tests/WhenMappingObjectRegression.cs index d6cf7776..68762568 100644 --- a/src/Mapster.Tests/WhenMappingObjectRegression.cs +++ b/src/Mapster.Tests/WhenMappingObjectRegression.cs @@ -47,7 +47,7 @@ public void UpdateToRealObject() var source = new Source524 { X1 = 123 }; var RealObject = new Object(); - var _result = source.Adapt(RealObject); + var _result = source.MapToTargetAdapt(RealObject); _result.ShouldBeOfType(); ((Source524)_result).X1.ShouldBe(source.X1); @@ -60,7 +60,7 @@ public void RealObjectCastToDestination() /// Warning potential Infinity Loop in var source = new Source524 { X1 = 123 }; var RealObject = new Object(); - var _result = RealObject.Adapt(source); + var _result = RealObject.MapToTargetAdapt(source); _result.ShouldBeOfType(); ((Source524)_result).X1.ShouldBe(source.X1); @@ -72,7 +72,7 @@ public void UpdateObjectInsaider() var _source = new InsaderObject() { X1 = 1 }; var _Destination = new InsaderObject() { X1 = 2 }; - var _result = _source.Adapt(_Destination); + var _result = _source.MapToTargetAdapt(_Destination); _result.X1.ShouldBe(_source.X1); } @@ -83,7 +83,7 @@ public void UpdateObjectInsaiderToObject() var _source = new InsaderObject() { X1 = 1 }; var _Destination = new InsaderObject() { X1 = new Object() }; - var _result = _source.Adapt(_Destination); + var _result = _source.MapToTargetAdapt(_Destination); _result.X1.ShouldBe(_source.X1); } @@ -94,7 +94,7 @@ public void UpdateObjectInsaiderWhenObjectinTSource() var _source = new InsaderObject() { X1 = new Object() }; var _Destination = new InsaderObject() { X1 = 3 }; - var _result = _source.Adapt(_Destination); + var _result = _source.MapToTargetAdapt(_Destination); _result.X1.ShouldBe(_source.X1); } @@ -105,7 +105,7 @@ public void UpdateObjectInsaiderWhenObjectinTSource() Dest524 Somemap(object source) { var dest = new Dest524 { X1 = 321 }; - var dest1 = source.Adapt(dest); + var dest1 = source.MapToTargetAdapt(dest); return dest; } @@ -113,7 +113,7 @@ Dest524 Somemap(object source) ManyDest524 SomemapManyDest(object source) { var dest = new ManyDest524 { X1 = 321, X2 = 127 }; - var dest1 = source.Adapt(dest); + var dest1 = source.MapToTargetAdapt(dest); return dest; } diff --git a/src/Mapster.Tests/WhenMappingPrimitiveCustomMappingRegression.cs b/src/Mapster.Tests/WhenMappingPrimitiveCustomMappingRegression.cs index d694ac67..0166b94c 100644 --- a/src/Mapster.Tests/WhenMappingPrimitiveCustomMappingRegression.cs +++ b/src/Mapster.Tests/WhenMappingPrimitiveCustomMappingRegression.cs @@ -44,8 +44,8 @@ public void MappingToPrimitiveInsiderWithCustomMapping() var target = new Source561 { Name = new Optional561("John") }.Adapt(); var TargetDestinationFromNull = new Target561() { Name = "Me" }; - var NullToupdateoptional = sourceNull.Adapt(TargetDestinationFromNull); - var _result = sourceNull.Adapt(target); + var NullToupdateoptional = sourceNull.MapToTargetAdapt(TargetDestinationFromNull); + var _result = sourceNull.MapToTargetAdapt(target); target.Name.ShouldBe("John"); NullToupdateoptional.Name.ShouldBe("Me"); diff --git a/src/Mapster.Tests/WhenMappingRecordRegression.cs b/src/Mapster.Tests/WhenMappingRecordRegression.cs index 9ba98adb..2e315c5d 100644 --- a/src/Mapster.Tests/WhenMappingRecordRegression.cs +++ b/src/Mapster.Tests/WhenMappingRecordRegression.cs @@ -23,9 +23,9 @@ public void AdaptRecordToRecord() var _destination = new TestRecordY() { X = 500 , Y = 200 }; var _destination2 = new TestRecordY() { X = 300, Y = 400 }; - var _result = _source.Adapt(_destination); + var _result = _source.MapToTargetAdapt(_destination); - var result2 = _destination.Adapt(_destination2); + var result2 = _destination.MapToTargetAdapt(_destination2); _result.X.ShouldBe(700); _result.Y.ShouldBe(200); @@ -37,7 +37,7 @@ public void AdaptPositionalRecordToPositionalRecord() { var _sourcePositional = new TestRecordPositional(600); var _destinationPositional = new TestRecordPositional(900); - var _positionalResult = _sourcePositional.Adapt(_destinationPositional); + var _positionalResult = _sourcePositional.MapToTargetAdapt(_destinationPositional); _positionalResult.X.ShouldBe(600); object.ReferenceEquals(_destinationPositional, _positionalResult).ShouldBeFalse(); @@ -48,7 +48,7 @@ public void AdaptRecordStructToRecordStruct() { var _sourceStruct = new TestRecordStruct() { X = 1000 }; var _destinationStruct = new TestRecordStruct() { X = 800 }; - var _structResult = _sourceStruct.Adapt(_destinationStruct); + var _structResult = _sourceStruct.MapToTargetAdapt(_destinationStruct); _structResult.X.ShouldBe(1000); _destinationStruct.X.Equals(_structResult.X).ShouldBeFalse(); @@ -59,7 +59,7 @@ public void AdaptRecordToClass() { var _sourсe = new TestRecordPositional(200); var _destination = new TestClassProtectedCtr(400); - var _result = _sourсe.Adapt(_destination); + var _result = _sourсe.MapToTargetAdapt(_destination); _destination.ShouldBeOfType(); _destination.X.ShouldBe(200); @@ -71,7 +71,7 @@ public void AdaptClassToRecord() { var _sourсe = new TestClassProtectedCtr(200); var _destination = new TestRecordPositional(400); - var _result = _sourсe.Adapt(_destination); + var _result = _sourсe.MapToTargetAdapt(_destination); _destination.ShouldBeOfType(); _result.X.ShouldBe(200); @@ -83,7 +83,7 @@ public void AdaptToSealtedRecord() { var _sourceRecord = new TestRecord() { X = 2000 }; var _destinationSealtedRecord = new TestSealedRecord() { X = 3000 }; - var _RecordResult = _sourceRecord.Adapt(_destinationSealtedRecord); + var _RecordResult = _sourceRecord.MapToTargetAdapt(_destinationSealtedRecord); _RecordResult.X.ShouldBe(2000); object.ReferenceEquals(_destinationSealtedRecord, _RecordResult).ShouldBeFalse(); @@ -94,7 +94,7 @@ public void AdaptToSealtedPositionalRecord() { var _sourceRecord = new TestRecord() { X = 2000 }; var _destinationSealtedPositionalRecord = new TestSealedRecordPositional(4000); - var _RecordResult = _sourceRecord.Adapt(_destinationSealtedPositionalRecord); + var _RecordResult = _sourceRecord.MapToTargetAdapt(_destinationSealtedPositionalRecord); _RecordResult.X.ShouldBe(2000); object.ReferenceEquals(_destinationSealtedPositionalRecord, _RecordResult).ShouldBeFalse(); @@ -105,7 +105,7 @@ public void AdaptClassToClassPublicCtrIsNotInstanse() { var _source = new TestClassPublicCtr(200); var _destination = new TestClassPublicCtr(400); - var _result = _source.Adapt(_destination); + var _result = _source.MapToTargetAdapt(_destination); _destination.ShouldBeOfType(); _destination.X.ShouldBe(200); @@ -117,7 +117,7 @@ public void AdaptClassToClassProtectdCtrIsNotInstanse() { var _source = new TestClassPublicCtr(200); var _destination = new TestClassProtectedCtr(400); - var _result = _source.Adapt(_destination); + var _result = _source.MapToTargetAdapt(_destination); _destination.ShouldBeOfType(); _destination.X.ShouldBe(200); @@ -154,7 +154,7 @@ public void AdaptClassToClassFromPrivatePropertyIsNotInstanse() { var _source = new TestClassPublicCtr(200); var _destination = new TestClassProtectedCtrPrivateProperty(400, "Me"); - var _result = _source.Adapt(_destination); + var _result = _source.MapToTargetAdapt(_destination); _destination.ShouldBeOfType(); _destination.X.ShouldBe(200); @@ -191,7 +191,7 @@ public void UpdateNullable() config.ForType() .IgnoreNullValues(true); - var _resultEmail = _updateEmail.Adapt(_sourceEmailUpdate, config); + var _resultEmail = _updateEmail.MapToTargetAdapt(_sourceEmailUpdate, config); _source.Id.ShouldBe("123"); _source.Created.ShouldBe(new DateTime(2023, 9, 24)); @@ -220,7 +220,7 @@ public void ImplicitOperatorCurrentWorkFromClass() pocoWithId1.Id.ToString().Equals(guid.ToString()).ShouldBeTrue(); pocoWithGuid2.Id.Equals(guid).ShouldBeTrue(); - var _result = pocoWithId1.Adapt(pocoWithGuid2); + var _result = pocoWithId1.MapToTargetAdapt(pocoWithGuid2); _result.Id.ToString().Equals(guid.ToString()).ShouldBeTrue(); // Guid value transmitted object.ReferenceEquals(_result, pocoWithGuid2).ShouldBeTrue(); // Not created new instanse from class pocoWithGuid2 @@ -233,7 +233,7 @@ public void DetectFakeRecord() { var _source = new TestClassPublicCtr(200); var _destination = new FakeRecord { X = 300 }; - var _result = _source.Adapt(_destination); + var _result = _source.MapToTargetAdapt(_destination); _destination.X.ShouldBe(200); object.ReferenceEquals(_destination, _result).ShouldBeTrue(); } @@ -245,7 +245,7 @@ public void OnlyInlineRecordWorked() var _sourceOnlyInitRecord = new OnlyInitRecord501 { MyInt = 2, MyString = "Hello World" }; var _resultOnlyinitRecord = _sourcePoco.Adapt(); - var _updateResult = _sourceOnlyInitRecord.Adapt(_resultOnlyinitRecord); + var _updateResult = _sourceOnlyInitRecord.MapToTargetAdapt(_resultOnlyinitRecord); _resultOnlyinitRecord.MyInt.ShouldBe(1); _resultOnlyinitRecord.MyString.ShouldBe("Hello"); @@ -260,7 +260,7 @@ public void MultyCtorRecordWorked() var _sourceMultyCtorRecord = new MultiCtorRecord (2, "Hello World"); var _resultMultyCtorRecord = _sourcePoco.Adapt(); - var _updateResult = _sourceMultyCtorRecord.Adapt(_resultMultyCtorRecord); + var _updateResult = _sourceMultyCtorRecord.MapToTargetAdapt(_resultMultyCtorRecord); _resultMultyCtorRecord.MyInt.ShouldBe(1); _resultMultyCtorRecord.MyString.ShouldBe("Hello"); @@ -275,7 +275,7 @@ public void MultiCtorAndInlineRecordWorked() var _sourceMultiCtorAndInline = new MultiCtorAndInlineRecord(2, "Hello World") { InitData = "Worked", MyEmail = "243@gmail.com" }; var _resultMultiCtorAndInline = _sourcePoco.Adapt(); - var _updateResult = _sourceMultiCtorAndInline.Adapt(_resultMultiCtorAndInline); + var _updateResult = _sourceMultiCtorAndInline.MapToTargetAdapt(_resultMultiCtorAndInline); _resultMultiCtorAndInline.MyInt.ShouldBe(1); _resultMultiCtorAndInline.MyString.ShouldBe("Hello"); @@ -340,12 +340,12 @@ public void MappingInterfaceToInterface() var TargetBase = sourceBase.Adapt(); var targetDerived = sourceDerived.Adapt(); - var update = targetDerived.Adapt(TargetBase); + var update = targetDerived.MapToTargetAdapt(TargetBase); var targetExtention = sourceExt.Adapt(); - var updExt = targetDerived.Adapt(targetExtention); + var updExt = targetDerived.MapToTargetAdapt(targetExtention); targetDerived.ShouldNotBeNull(); targetDerived.ShouldSatisfyAllConditions( @@ -381,9 +381,9 @@ public void WhenRecordReceivedIgnoreCtorParamProcessing() var UserInsider = new UserInside(user, new UserRecord456("Skot")); var map = userDto.Adapt(); - var maptoTarget = userDto.Adapt(user); + var maptoTarget = userDto.MapToTargetAdapt(user); - var MapToTargetInsider = DtoInsider.Adapt(UserInsider); + var MapToTargetInsider = DtoInsider.MapToTargetAdapt(UserInsider); map.Name.ShouldBeNullOrEmpty(); // Ignore is work set default value maptoTarget.Name.ShouldBe("John"); // Ignore is work ignored member save value from Destination @@ -409,7 +409,7 @@ public void WhenRecordTypeWorksWithUseDestinationValueAndIgnoreNullValues() var txt = _sourceFromMapToTarget.BuildAdapter().CreateMapToTargetExpression(); - var _resultMapToTarget = _sourceFromMapToTarget.Adapt(result); + var _resultMapToTarget = _sourceFromMapToTarget.MapToTargetAdapt(result); result.A.ShouldBe(0); // default Value - not match result.S.ShouldBe("Inside Data"); // is not AutoProperty not mod by source @@ -436,7 +436,7 @@ public void FixCtorParamMapping() var result = new CreateOrderRequest771(sourceRequestOrderDto).Adapt(); - var resultID = db.Adapt(new Database746()); + var resultID = db.MapToTargetAdapt(new Database746()); result.Order.Payment.CVV.ShouldBe("234"); @@ -455,7 +455,7 @@ public void RequiredProperty() var s = source.BuildAdapter().CreateMapToTargetExpression(); - var result = source.Adapt(destination); + var result = source.MapToTargetAdapt(destination); result.ID.ShouldBe(245); result.FirstMidName.ShouldBe(source.FirstMidName); @@ -477,7 +477,7 @@ public void CollectionUpdate() new(234) }; var destination = new List(); - var _result = sources.Adapt(destination); + var _result = sources.MapToTargetAdapt(destination); destination.Count.ShouldBe(_result.Count); } diff --git a/src/Mapster.Tests/WhenMappingStructRegression.cs b/src/Mapster.Tests/WhenMappingStructRegression.cs index 43ad1882..d43e3f4f 100644 --- a/src/Mapster.Tests/WhenMappingStructRegression.cs +++ b/src/Mapster.Tests/WhenMappingStructRegression.cs @@ -49,7 +49,7 @@ public void TestMapStructToExistingStruct() { Ignore = "Ignored property", }; - dest = source.Adapt(dest); + dest = source.MapToTargetAdapt(dest); dest.Ignore.ShouldBe("Ignored property"); dest.Name.ShouldBe("Some Name"); @@ -71,7 +71,7 @@ public void TestMapClassToExistingStruct() { Ignore = "Ignored property", }; - dest = source.Adapt(dest); + dest = source.MapToTargetAdapt(dest); dest.Ignore.ShouldBe("Ignored property"); dest.Name.ShouldBe("Some Name"); diff --git a/src/Mapster.Tests/WhenMappingWithAdaptIgnoreRegression.cs b/src/Mapster.Tests/WhenMappingWithAdaptIgnoreRegression.cs index 13638083..f0f9eaff 100644 --- a/src/Mapster.Tests/WhenMappingWithAdaptIgnoreRegression.cs +++ b/src/Mapster.Tests/WhenMappingWithAdaptIgnoreRegression.cs @@ -47,7 +47,7 @@ public void TestMapStructToExistingStruct() var destination = new Poco() { Name = "Destination", State = 2 }; var source = new Dto() { Name = "Source" }; - var result = source.Adapt(destination); + var result = source.MapToTargetAdapt(destination); result.State.ShouldBe(2); result.Name.ShouldBe("Source"); } diff --git a/src/Mapster.Tests/WhenMappingWithSecondSourceObject.cs b/src/Mapster.Tests/WhenMappingWithSecondSourceObject.cs index a3b31181..d5128d13 100644 --- a/src/Mapster.Tests/WhenMappingWithSecondSourceObject.cs +++ b/src/Mapster.Tests/WhenMappingWithSecondSourceObject.cs @@ -53,7 +53,7 @@ public void TestMapFromSecondSourceObject() generatedType.Name.ShouldBe("Name 1"); generatedType.Address.ShouldBe("Address 1"); - generatedType = c2.Adapt(generatedType); + generatedType = c2.MapToTargetAdapt(generatedType); generatedType.Id.ShouldBe(2); generatedType.Name.ShouldBe("Name 2"); diff --git a/src/Mapster.Tests/WhenPerformingAfterMapping.cs b/src/Mapster.Tests/WhenPerformingAfterMapping.cs index 68b06a62..c8ab5341 100644 --- a/src/Mapster.Tests/WhenPerformingAfterMapping.cs +++ b/src/Mapster.Tests/WhenPerformingAfterMapping.cs @@ -87,7 +87,7 @@ public void MapToTarget_Support_Destination_Parameter() Name = "test", }; var oldDto = new SimpleDto { Name = "zzz", }; - var result = poco.Adapt(oldDto); + var result = poco.MapToTargetAdapt(oldDto); result.ShouldNotBeSameAs(oldDto); result.Id.ShouldBe(poco.Id); diff --git a/src/Mapster.Tests/WhenPerformingBeforeMapping.cs b/src/Mapster.Tests/WhenPerformingBeforeMapping.cs index 5c000802..9d7bc666 100644 --- a/src/Mapster.Tests/WhenPerformingBeforeMapping.cs +++ b/src/Mapster.Tests/WhenPerformingBeforeMapping.cs @@ -67,7 +67,7 @@ public void MapToTarget_Support_Destination_Parameter() IEnumerable source = new List { 1, 2, 3, }; IEnumerable destination = new List { 0, }; - var result = source.Adapt(destination); + var result = source.MapToTargetAdapt(destination); destination.ShouldBe(new List { 0, }); source.ShouldBe(new List { 1, 2, 3, }); diff --git a/src/Mapster/TypeAdapters/TypeAdapterToTarget.cs b/src/Mapster/TypeAdapters/TypeAdapterToTarget.cs index 0e82e3d5..fa4de9d6 100644 --- a/src/Mapster/TypeAdapters/TypeAdapterToTarget.cs +++ b/src/Mapster/TypeAdapters/TypeAdapterToTarget.cs @@ -5,19 +5,6 @@ namespace Mapster { public static partial class TypeAdapter { - /// - /// Adapt the source object to the existing destination object. - /// - /// Source type. - /// Destination type. - /// Source object to adapt. - /// The destination object to populate. - /// Adapted destination type. - public static TDestination Adapt(this TSource source, TDestination destination) - { - return Adapt(source, destination, TypeAdapterConfig.GlobalSettings); - } - /// /// Adapt the source object to the existing destination object. /// @@ -26,38 +13,22 @@ public static TDestination Adapt(this TSource source, TDe /// Source object to adapt. /// The destination object to populate. /// Configuration - /// Adapted destination type. - public static TDestination Adapt(this TSource source, TDestination destination, TypeAdapterConfig config) + public static void Adapt(this TSource source, TDestination destination, TypeAdapterConfig? config = null) where TDestination : class { var sourceType = source?.GetType(); var destinationType = destination?.GetType(); + if(config is null) + config = TypeAdapterConfig.GlobalSettings; + if (sourceType == typeof(object)) // Infinity loop in ObjectAdapter if Runtime Type of source is Object - return destination; + return; if (typeof(TSource) == typeof(object) || typeof(TDestination) == typeof(object)) - return UpdateFuncFromPackedinObject(source, destination, config, sourceType, destinationType); + UpdateFuncFromPackedinObject(source, destination, config, sourceType, destinationType); var fn = config.GetMapToTargetFunction(); - return fn(source, destination); - } - - private static TDestination UpdateFuncFromPackedinObject(TSource source, TDestination destination, TypeAdapterConfig config, Type sourceType, Type destinationType) - { - dynamic del = config.GetMapToTargetFunction(sourceType, destinationType); - - - if (sourceType.GetTypeInfo().IsVisible && destinationType.GetTypeInfo().IsVisible) - { - dynamic objfn = del; - return objfn((dynamic)source, (dynamic)destination); - } - else - { - //NOTE: if type is non-public, we cannot use dynamic - //DynamicInvoke is slow, but works with non-public - return (TDestination)del.DynamicInvoke(source, destination); - } + fn(source, destination); } /// @@ -98,5 +69,49 @@ private static TDestination UpdateFuncFromPackedinObject( } } + /// + /// Adapt the source object to the Immutable type base object. + /// + /// Source type. + /// Destination type. + /// Source object to adapt. + /// Instance of Immutable type. + /// Configuration + /// Nondestructive mutation baseValue using tranformed from source object values + public static TDestination MapToTargetAdapt(this TSource source, TDestination baseValue, TypeAdapterConfig? config = null) + { + var sourceType = source?.GetType(); + var destinationType = baseValue?.GetType(); + + if (config is null) + config = TypeAdapterConfig.GlobalSettings; + + if (sourceType == typeof(object)) // Infinity loop in ObjectAdapter if Runtime Type of source is Object + return baseValue; + + if (typeof(TSource) == typeof(object) || typeof(TDestination) == typeof(object)) + return UpdateFuncFromPackedinObject(source, baseValue, config, sourceType, destinationType); + + var fn = config.GetMapToTargetFunction(); + return fn(source, baseValue); + } + + private static TDestination UpdateFuncFromPackedinObject(TSource source, TDestination destination, TypeAdapterConfig config, Type sourceType, Type destinationType) + { + dynamic del = config.GetMapToTargetFunction(sourceType, destinationType); + + + if (sourceType.GetTypeInfo().IsVisible && destinationType.GetTypeInfo().IsVisible) + { + dynamic objfn = del; + return objfn((dynamic)source, (dynamic)destination); + } + else + { + //NOTE: if type is non-public, we cannot use dynamic + //DynamicInvoke is slow, but works with non-public + return (TDestination)del.DynamicInvoke(source, destination); + } + } } } From 5f65cdac657d9e66862e449df765348f41838ea2 Mon Sep 17 00:00:00 2001 From: DocSvartz Date: Sat, 13 Dec 2025 06:30:18 +0500 Subject: [PATCH 5/6] Rename to AdaptTotarget and check Record --- src/Mapster.Tests/WhenForkingConfig.cs | 2 +- src/Mapster.Tests/WhenIgnoreMapping.cs | 2 +- .../WhenMappingIgnoreNullValues.cs | 2 +- src/Mapster.Tests/WhenMappingInitProperty.cs | 4 +- .../WhenMappingNullableEnumRegression.cs | 2 +- .../WhenMappingObjectRegression.cs | 14 ++--- ...MappingPrimitiveCustomMappingRegression.cs | 4 +- .../WhenMappingRecordRegression.cs | 56 +++++++++---------- .../WhenMappingStructRegression.cs | 4 +- .../WhenMappingWithAdaptIgnoreRegression.cs | 2 +- .../WhenMappingWithSecondSourceObject.cs | 2 +- .../WhenPerformingAfterMapping.cs | 2 +- .../WhenPerformingBeforeMapping.cs | 2 +- .../TypeAdapters/TypeAdapterToTarget.cs | 5 +- 14 files changed, 53 insertions(+), 50 deletions(-) diff --git a/src/Mapster.Tests/WhenForkingConfig.cs b/src/Mapster.Tests/WhenForkingConfig.cs index 2b33c23b..59aa9050 100644 --- a/src/Mapster.Tests/WhenForkingConfig.cs +++ b/src/Mapster.Tests/WhenForkingConfig.cs @@ -65,7 +65,7 @@ public void Fork_Setting() dto.Name1.ShouldBe(poco.Name1); dto.Name2.ShouldBe("Bar"); - var str = poco.Name2.MapToTargetAdapt(dto.Name2, config); + var str = poco.Name2.AdaptToTarget(dto.Name2, config); str.ShouldBe(poco.Name2); } diff --git a/src/Mapster.Tests/WhenIgnoreMapping.cs b/src/Mapster.Tests/WhenIgnoreMapping.cs index 233b76f4..b5d3eef3 100644 --- a/src/Mapster.Tests/WhenIgnoreMapping.cs +++ b/src/Mapster.Tests/WhenIgnoreMapping.cs @@ -83,7 +83,7 @@ public void WhenClassIgnoreCtorParamGetDefaultValue() var dest = new B707(123, "Hello"); var docKind = source.Adapt(config); - var mapTotarget = source.MapToTargetAdapt(dest,config); + var mapTotarget = source.AdaptToTarget(dest,config); docKind.Id.ShouldBe(0); mapTotarget.Id.ShouldBe(123); diff --git a/src/Mapster.Tests/WhenMappingIgnoreNullValues.cs b/src/Mapster.Tests/WhenMappingIgnoreNullValues.cs index ab7d7bf4..d420849e 100644 --- a/src/Mapster.Tests/WhenMappingIgnoreNullValues.cs +++ b/src/Mapster.Tests/WhenMappingIgnoreNullValues.cs @@ -31,7 +31,7 @@ public void Map_To_Target() .Compile(); var source = new SourceClass(); - var dest = source.MapToTargetAdapt(new DestClass()); + var dest = source.AdaptToTarget(new DestClass()); Assert.AreEqual("Hello", dest.Title); Assert.IsNotNull(dest.Sub); diff --git a/src/Mapster.Tests/WhenMappingInitProperty.cs b/src/Mapster.Tests/WhenMappingInitProperty.cs index f1ec62ee..7dc55d18 100644 --- a/src/Mapster.Tests/WhenMappingInitProperty.cs +++ b/src/Mapster.Tests/WhenMappingInitProperty.cs @@ -17,7 +17,7 @@ public void WhenMappingToHiddenandNewInitFieldDestination() { var source = new Source672() { Id = 156}; var c = source.Adapt(); - var s = source.MapToTargetAdapt(new BDestination()); + var s = source.AdaptToTarget(new BDestination()); ((ADestination)c).Id.ShouldBe(default); // Hidden Base member is not mapping s.Id.ShouldBe(156); @@ -31,7 +31,7 @@ public void WhenMappingToHiddenandNewInitFieldWithConstructUsing() var source = new Source672() { Id = 256 }; var c = source.Adapt(); - var s = source.MapToTargetAdapt(new BDestination()); + var s = source.AdaptToTarget(new BDestination()); ((ADestination)c).Id.ShouldBe(default); // Hidden Base member is not mapping s.Id.ShouldBe(256); diff --git a/src/Mapster.Tests/WhenMappingNullableEnumRegression.cs b/src/Mapster.Tests/WhenMappingNullableEnumRegression.cs index d6e1c49f..9276002a 100644 --- a/src/Mapster.Tests/WhenMappingNullableEnumRegression.cs +++ b/src/Mapster.Tests/WhenMappingNullableEnumRegression.cs @@ -47,7 +47,7 @@ public void UpdateNullEnumToClass() var mDest2 = new MyDestination() { TypeEmployer = new KeyValueData("Admin", null) }; var _MyDestination = myClass?.Adapt(); // Work - var _result = _MyDestination.MapToTargetAdapt(mDest2); + var _result = _MyDestination.AdaptToTarget(mDest2); _result.TypeEmployer.Key.ShouldBe(MyEnum.User.ToString()); } diff --git a/src/Mapster.Tests/WhenMappingObjectRegression.cs b/src/Mapster.Tests/WhenMappingObjectRegression.cs index 68762568..45bb1972 100644 --- a/src/Mapster.Tests/WhenMappingObjectRegression.cs +++ b/src/Mapster.Tests/WhenMappingObjectRegression.cs @@ -47,7 +47,7 @@ public void UpdateToRealObject() var source = new Source524 { X1 = 123 }; var RealObject = new Object(); - var _result = source.MapToTargetAdapt(RealObject); + var _result = source.AdaptToTarget(RealObject); _result.ShouldBeOfType(); ((Source524)_result).X1.ShouldBe(source.X1); @@ -60,7 +60,7 @@ public void RealObjectCastToDestination() /// Warning potential Infinity Loop in var source = new Source524 { X1 = 123 }; var RealObject = new Object(); - var _result = RealObject.MapToTargetAdapt(source); + var _result = RealObject.AdaptToTarget(source); _result.ShouldBeOfType(); ((Source524)_result).X1.ShouldBe(source.X1); @@ -72,7 +72,7 @@ public void UpdateObjectInsaider() var _source = new InsaderObject() { X1 = 1 }; var _Destination = new InsaderObject() { X1 = 2 }; - var _result = _source.MapToTargetAdapt(_Destination); + var _result = _source.AdaptToTarget(_Destination); _result.X1.ShouldBe(_source.X1); } @@ -83,7 +83,7 @@ public void UpdateObjectInsaiderToObject() var _source = new InsaderObject() { X1 = 1 }; var _Destination = new InsaderObject() { X1 = new Object() }; - var _result = _source.MapToTargetAdapt(_Destination); + var _result = _source.AdaptToTarget(_Destination); _result.X1.ShouldBe(_source.X1); } @@ -94,7 +94,7 @@ public void UpdateObjectInsaiderWhenObjectinTSource() var _source = new InsaderObject() { X1 = new Object() }; var _Destination = new InsaderObject() { X1 = 3 }; - var _result = _source.MapToTargetAdapt(_Destination); + var _result = _source.AdaptToTarget(_Destination); _result.X1.ShouldBe(_source.X1); } @@ -105,7 +105,7 @@ public void UpdateObjectInsaiderWhenObjectinTSource() Dest524 Somemap(object source) { var dest = new Dest524 { X1 = 321 }; - var dest1 = source.MapToTargetAdapt(dest); + var dest1 = source.AdaptToTarget(dest); return dest; } @@ -113,7 +113,7 @@ Dest524 Somemap(object source) ManyDest524 SomemapManyDest(object source) { var dest = new ManyDest524 { X1 = 321, X2 = 127 }; - var dest1 = source.MapToTargetAdapt(dest); + var dest1 = source.AdaptToTarget(dest); return dest; } diff --git a/src/Mapster.Tests/WhenMappingPrimitiveCustomMappingRegression.cs b/src/Mapster.Tests/WhenMappingPrimitiveCustomMappingRegression.cs index 0166b94c..76b1b8c8 100644 --- a/src/Mapster.Tests/WhenMappingPrimitiveCustomMappingRegression.cs +++ b/src/Mapster.Tests/WhenMappingPrimitiveCustomMappingRegression.cs @@ -44,8 +44,8 @@ public void MappingToPrimitiveInsiderWithCustomMapping() var target = new Source561 { Name = new Optional561("John") }.Adapt(); var TargetDestinationFromNull = new Target561() { Name = "Me" }; - var NullToupdateoptional = sourceNull.MapToTargetAdapt(TargetDestinationFromNull); - var _result = sourceNull.MapToTargetAdapt(target); + var NullToupdateoptional = sourceNull.AdaptToTarget(TargetDestinationFromNull); + var _result = sourceNull.AdaptToTarget(target); target.Name.ShouldBe("John"); NullToupdateoptional.Name.ShouldBe("Me"); diff --git a/src/Mapster.Tests/WhenMappingRecordRegression.cs b/src/Mapster.Tests/WhenMappingRecordRegression.cs index 2e315c5d..1ed1c21f 100644 --- a/src/Mapster.Tests/WhenMappingRecordRegression.cs +++ b/src/Mapster.Tests/WhenMappingRecordRegression.cs @@ -23,13 +23,13 @@ public void AdaptRecordToRecord() var _destination = new TestRecordY() { X = 500 , Y = 200 }; var _destination2 = new TestRecordY() { X = 300, Y = 400 }; - var _result = _source.MapToTargetAdapt(_destination); + _source.Adapt(_destination); - var result2 = _destination.MapToTargetAdapt(_destination2); + var result2 = _destination.AdaptToTarget(_destination2); - _result.X.ShouldBe(700); - _result.Y.ShouldBe(200); - object.ReferenceEquals(_result, _destination).ShouldBeFalse(); + // _result.X.ShouldBe(700); + // _result.Y.ShouldBe(200); + // object.ReferenceEquals(_result, _destination).ShouldBeFalse(); } [TestMethod] @@ -37,7 +37,7 @@ public void AdaptPositionalRecordToPositionalRecord() { var _sourcePositional = new TestRecordPositional(600); var _destinationPositional = new TestRecordPositional(900); - var _positionalResult = _sourcePositional.MapToTargetAdapt(_destinationPositional); + var _positionalResult = _sourcePositional.AdaptToTarget(_destinationPositional); _positionalResult.X.ShouldBe(600); object.ReferenceEquals(_destinationPositional, _positionalResult).ShouldBeFalse(); @@ -48,7 +48,7 @@ public void AdaptRecordStructToRecordStruct() { var _sourceStruct = new TestRecordStruct() { X = 1000 }; var _destinationStruct = new TestRecordStruct() { X = 800 }; - var _structResult = _sourceStruct.MapToTargetAdapt(_destinationStruct); + var _structResult = _sourceStruct.AdaptToTarget(_destinationStruct); _structResult.X.ShouldBe(1000); _destinationStruct.X.Equals(_structResult.X).ShouldBeFalse(); @@ -59,7 +59,7 @@ public void AdaptRecordToClass() { var _sourсe = new TestRecordPositional(200); var _destination = new TestClassProtectedCtr(400); - var _result = _sourсe.MapToTargetAdapt(_destination); + var _result = _sourсe.AdaptToTarget(_destination); _destination.ShouldBeOfType(); _destination.X.ShouldBe(200); @@ -71,7 +71,7 @@ public void AdaptClassToRecord() { var _sourсe = new TestClassProtectedCtr(200); var _destination = new TestRecordPositional(400); - var _result = _sourсe.MapToTargetAdapt(_destination); + var _result = _sourсe.AdaptToTarget(_destination); _destination.ShouldBeOfType(); _result.X.ShouldBe(200); @@ -83,7 +83,7 @@ public void AdaptToSealtedRecord() { var _sourceRecord = new TestRecord() { X = 2000 }; var _destinationSealtedRecord = new TestSealedRecord() { X = 3000 }; - var _RecordResult = _sourceRecord.MapToTargetAdapt(_destinationSealtedRecord); + var _RecordResult = _sourceRecord.AdaptToTarget(_destinationSealtedRecord); _RecordResult.X.ShouldBe(2000); object.ReferenceEquals(_destinationSealtedRecord, _RecordResult).ShouldBeFalse(); @@ -94,7 +94,7 @@ public void AdaptToSealtedPositionalRecord() { var _sourceRecord = new TestRecord() { X = 2000 }; var _destinationSealtedPositionalRecord = new TestSealedRecordPositional(4000); - var _RecordResult = _sourceRecord.MapToTargetAdapt(_destinationSealtedPositionalRecord); + var _RecordResult = _sourceRecord.AdaptToTarget(_destinationSealtedPositionalRecord); _RecordResult.X.ShouldBe(2000); object.ReferenceEquals(_destinationSealtedPositionalRecord, _RecordResult).ShouldBeFalse(); @@ -105,7 +105,7 @@ public void AdaptClassToClassPublicCtrIsNotInstanse() { var _source = new TestClassPublicCtr(200); var _destination = new TestClassPublicCtr(400); - var _result = _source.MapToTargetAdapt(_destination); + var _result = _source.AdaptToTarget(_destination); _destination.ShouldBeOfType(); _destination.X.ShouldBe(200); @@ -117,7 +117,7 @@ public void AdaptClassToClassProtectdCtrIsNotInstanse() { var _source = new TestClassPublicCtr(200); var _destination = new TestClassProtectedCtr(400); - var _result = _source.MapToTargetAdapt(_destination); + var _result = _source.AdaptToTarget(_destination); _destination.ShouldBeOfType(); _destination.X.ShouldBe(200); @@ -154,7 +154,7 @@ public void AdaptClassToClassFromPrivatePropertyIsNotInstanse() { var _source = new TestClassPublicCtr(200); var _destination = new TestClassProtectedCtrPrivateProperty(400, "Me"); - var _result = _source.MapToTargetAdapt(_destination); + var _result = _source.AdaptToTarget(_destination); _destination.ShouldBeOfType(); _destination.X.ShouldBe(200); @@ -191,7 +191,7 @@ public void UpdateNullable() config.ForType() .IgnoreNullValues(true); - var _resultEmail = _updateEmail.MapToTargetAdapt(_sourceEmailUpdate, config); + var _resultEmail = _updateEmail.AdaptToTarget(_sourceEmailUpdate, config); _source.Id.ShouldBe("123"); _source.Created.ShouldBe(new DateTime(2023, 9, 24)); @@ -220,7 +220,7 @@ public void ImplicitOperatorCurrentWorkFromClass() pocoWithId1.Id.ToString().Equals(guid.ToString()).ShouldBeTrue(); pocoWithGuid2.Id.Equals(guid).ShouldBeTrue(); - var _result = pocoWithId1.MapToTargetAdapt(pocoWithGuid2); + var _result = pocoWithId1.AdaptToTarget(pocoWithGuid2); _result.Id.ToString().Equals(guid.ToString()).ShouldBeTrue(); // Guid value transmitted object.ReferenceEquals(_result, pocoWithGuid2).ShouldBeTrue(); // Not created new instanse from class pocoWithGuid2 @@ -233,7 +233,7 @@ public void DetectFakeRecord() { var _source = new TestClassPublicCtr(200); var _destination = new FakeRecord { X = 300 }; - var _result = _source.MapToTargetAdapt(_destination); + var _result = _source.AdaptToTarget(_destination); _destination.X.ShouldBe(200); object.ReferenceEquals(_destination, _result).ShouldBeTrue(); } @@ -245,7 +245,7 @@ public void OnlyInlineRecordWorked() var _sourceOnlyInitRecord = new OnlyInitRecord501 { MyInt = 2, MyString = "Hello World" }; var _resultOnlyinitRecord = _sourcePoco.Adapt(); - var _updateResult = _sourceOnlyInitRecord.MapToTargetAdapt(_resultOnlyinitRecord); + var _updateResult = _sourceOnlyInitRecord.AdaptToTarget(_resultOnlyinitRecord); _resultOnlyinitRecord.MyInt.ShouldBe(1); _resultOnlyinitRecord.MyString.ShouldBe("Hello"); @@ -260,7 +260,7 @@ public void MultyCtorRecordWorked() var _sourceMultyCtorRecord = new MultiCtorRecord (2, "Hello World"); var _resultMultyCtorRecord = _sourcePoco.Adapt(); - var _updateResult = _sourceMultyCtorRecord.MapToTargetAdapt(_resultMultyCtorRecord); + var _updateResult = _sourceMultyCtorRecord.AdaptToTarget(_resultMultyCtorRecord); _resultMultyCtorRecord.MyInt.ShouldBe(1); _resultMultyCtorRecord.MyString.ShouldBe("Hello"); @@ -275,7 +275,7 @@ public void MultiCtorAndInlineRecordWorked() var _sourceMultiCtorAndInline = new MultiCtorAndInlineRecord(2, "Hello World") { InitData = "Worked", MyEmail = "243@gmail.com" }; var _resultMultiCtorAndInline = _sourcePoco.Adapt(); - var _updateResult = _sourceMultiCtorAndInline.MapToTargetAdapt(_resultMultiCtorAndInline); + var _updateResult = _sourceMultiCtorAndInline.AdaptToTarget(_resultMultiCtorAndInline); _resultMultiCtorAndInline.MyInt.ShouldBe(1); _resultMultiCtorAndInline.MyString.ShouldBe("Hello"); @@ -340,12 +340,12 @@ public void MappingInterfaceToInterface() var TargetBase = sourceBase.Adapt(); var targetDerived = sourceDerived.Adapt(); - var update = targetDerived.MapToTargetAdapt(TargetBase); + var update = targetDerived.AdaptToTarget(TargetBase); var targetExtention = sourceExt.Adapt(); - var updExt = targetDerived.MapToTargetAdapt(targetExtention); + var updExt = targetDerived.AdaptToTarget(targetExtention); targetDerived.ShouldNotBeNull(); targetDerived.ShouldSatisfyAllConditions( @@ -381,9 +381,9 @@ public void WhenRecordReceivedIgnoreCtorParamProcessing() var UserInsider = new UserInside(user, new UserRecord456("Skot")); var map = userDto.Adapt(); - var maptoTarget = userDto.MapToTargetAdapt(user); + var maptoTarget = userDto.AdaptToTarget(user); - var MapToTargetInsider = DtoInsider.MapToTargetAdapt(UserInsider); + var MapToTargetInsider = DtoInsider.AdaptToTarget(UserInsider); map.Name.ShouldBeNullOrEmpty(); // Ignore is work set default value maptoTarget.Name.ShouldBe("John"); // Ignore is work ignored member save value from Destination @@ -409,7 +409,7 @@ public void WhenRecordTypeWorksWithUseDestinationValueAndIgnoreNullValues() var txt = _sourceFromMapToTarget.BuildAdapter().CreateMapToTargetExpression(); - var _resultMapToTarget = _sourceFromMapToTarget.MapToTargetAdapt(result); + var _resultMapToTarget = _sourceFromMapToTarget.AdaptToTarget(result); result.A.ShouldBe(0); // default Value - not match result.S.ShouldBe("Inside Data"); // is not AutoProperty not mod by source @@ -436,7 +436,7 @@ public void FixCtorParamMapping() var result = new CreateOrderRequest771(sourceRequestOrderDto).Adapt(); - var resultID = db.MapToTargetAdapt(new Database746()); + var resultID = db.AdaptToTarget(new Database746()); result.Order.Payment.CVV.ShouldBe("234"); @@ -455,7 +455,7 @@ public void RequiredProperty() var s = source.BuildAdapter().CreateMapToTargetExpression(); - var result = source.MapToTargetAdapt(destination); + var result = source.AdaptToTarget(destination); result.ID.ShouldBe(245); result.FirstMidName.ShouldBe(source.FirstMidName); @@ -477,7 +477,7 @@ public void CollectionUpdate() new(234) }; var destination = new List(); - var _result = sources.MapToTargetAdapt(destination); + var _result = sources.AdaptToTarget(destination); destination.Count.ShouldBe(_result.Count); } diff --git a/src/Mapster.Tests/WhenMappingStructRegression.cs b/src/Mapster.Tests/WhenMappingStructRegression.cs index d43e3f4f..ad569421 100644 --- a/src/Mapster.Tests/WhenMappingStructRegression.cs +++ b/src/Mapster.Tests/WhenMappingStructRegression.cs @@ -49,7 +49,7 @@ public void TestMapStructToExistingStruct() { Ignore = "Ignored property", }; - dest = source.MapToTargetAdapt(dest); + dest = source.AdaptToTarget(dest); dest.Ignore.ShouldBe("Ignored property"); dest.Name.ShouldBe("Some Name"); @@ -71,7 +71,7 @@ public void TestMapClassToExistingStruct() { Ignore = "Ignored property", }; - dest = source.MapToTargetAdapt(dest); + dest = source.AdaptToTarget(dest); dest.Ignore.ShouldBe("Ignored property"); dest.Name.ShouldBe("Some Name"); diff --git a/src/Mapster.Tests/WhenMappingWithAdaptIgnoreRegression.cs b/src/Mapster.Tests/WhenMappingWithAdaptIgnoreRegression.cs index f0f9eaff..4254bbde 100644 --- a/src/Mapster.Tests/WhenMappingWithAdaptIgnoreRegression.cs +++ b/src/Mapster.Tests/WhenMappingWithAdaptIgnoreRegression.cs @@ -47,7 +47,7 @@ public void TestMapStructToExistingStruct() var destination = new Poco() { Name = "Destination", State = 2 }; var source = new Dto() { Name = "Source" }; - var result = source.MapToTargetAdapt(destination); + var result = source.AdaptToTarget(destination); result.State.ShouldBe(2); result.Name.ShouldBe("Source"); } diff --git a/src/Mapster.Tests/WhenMappingWithSecondSourceObject.cs b/src/Mapster.Tests/WhenMappingWithSecondSourceObject.cs index d5128d13..13b9e530 100644 --- a/src/Mapster.Tests/WhenMappingWithSecondSourceObject.cs +++ b/src/Mapster.Tests/WhenMappingWithSecondSourceObject.cs @@ -53,7 +53,7 @@ public void TestMapFromSecondSourceObject() generatedType.Name.ShouldBe("Name 1"); generatedType.Address.ShouldBe("Address 1"); - generatedType = c2.MapToTargetAdapt(generatedType); + generatedType = c2.AdaptToTarget(generatedType); generatedType.Id.ShouldBe(2); generatedType.Name.ShouldBe("Name 2"); diff --git a/src/Mapster.Tests/WhenPerformingAfterMapping.cs b/src/Mapster.Tests/WhenPerformingAfterMapping.cs index c8ab5341..e2442702 100644 --- a/src/Mapster.Tests/WhenPerformingAfterMapping.cs +++ b/src/Mapster.Tests/WhenPerformingAfterMapping.cs @@ -87,7 +87,7 @@ public void MapToTarget_Support_Destination_Parameter() Name = "test", }; var oldDto = new SimpleDto { Name = "zzz", }; - var result = poco.MapToTargetAdapt(oldDto); + var result = poco.AdaptToTarget(oldDto); result.ShouldNotBeSameAs(oldDto); result.Id.ShouldBe(poco.Id); diff --git a/src/Mapster.Tests/WhenPerformingBeforeMapping.cs b/src/Mapster.Tests/WhenPerformingBeforeMapping.cs index 9d7bc666..1068f293 100644 --- a/src/Mapster.Tests/WhenPerformingBeforeMapping.cs +++ b/src/Mapster.Tests/WhenPerformingBeforeMapping.cs @@ -67,7 +67,7 @@ public void MapToTarget_Support_Destination_Parameter() IEnumerable source = new List { 1, 2, 3, }; IEnumerable destination = new List { 0, }; - var result = source.MapToTargetAdapt(destination); + var result = source.AdaptToTarget(destination); destination.ShouldBe(new List { 0, }); source.ShouldBe(new List { 1, 2, 3, }); diff --git a/src/Mapster/TypeAdapters/TypeAdapterToTarget.cs b/src/Mapster/TypeAdapters/TypeAdapterToTarget.cs index fa4de9d6..74b3013c 100644 --- a/src/Mapster/TypeAdapters/TypeAdapterToTarget.cs +++ b/src/Mapster/TypeAdapters/TypeAdapterToTarget.cs @@ -15,6 +15,9 @@ public static partial class TypeAdapter /// Configuration public static void Adapt(this TSource source, TDestination destination, TypeAdapterConfig? config = null) where TDestination : class { + if (typeof(TDestination).IsRecordType()) + throw new InvalidOperationException($"Type: {typeof(TDestination).Name} is Immutable Using AdaptToTarget"); + var sourceType = source?.GetType(); var destinationType = destination?.GetType(); @@ -78,7 +81,7 @@ public static void Adapt(this TSource source, TDestinatio /// Instance of Immutable type. /// Configuration /// Nondestructive mutation baseValue using tranformed from source object values - public static TDestination MapToTargetAdapt(this TSource source, TDestination baseValue, TypeAdapterConfig? config = null) + public static TDestination AdaptToTarget(this TSource source, TDestination baseValue, TypeAdapterConfig? config = null) { var sourceType = source?.GetType(); var destinationType = baseValue?.GetType(); From c7a3625c29bc9585823753e36f1178dac16a30a3 Mon Sep 17 00:00:00 2001 From: DocSvartz Date: Sat, 13 Dec 2025 06:35:46 +0500 Subject: [PATCH 6/6] restore test --- src/Mapster.Tests/WhenMappingRecordRegression.cs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/Mapster.Tests/WhenMappingRecordRegression.cs b/src/Mapster.Tests/WhenMappingRecordRegression.cs index 1ed1c21f..305dae77 100644 --- a/src/Mapster.Tests/WhenMappingRecordRegression.cs +++ b/src/Mapster.Tests/WhenMappingRecordRegression.cs @@ -21,15 +21,14 @@ public void AdaptRecordToRecord() var _source = new TestRecord() { X = 700 }; var _destination = new TestRecordY() { X = 500 , Y = 200 }; - var _destination2 = new TestRecordY() { X = 300, Y = 400 }; - _source.Adapt(_destination); - + + var _result = _source.AdaptToTarget(_destination); var result2 = _destination.AdaptToTarget(_destination2); - // _result.X.ShouldBe(700); - // _result.Y.ShouldBe(200); - // object.ReferenceEquals(_result, _destination).ShouldBeFalse(); + _result.X.ShouldBe(700); + _result.Y.ShouldBe(200); + object.ReferenceEquals(_result, _destination).ShouldBeFalse(); } [TestMethod]