diff --git a/src/Mapster.Tests/WhenUseTempAdapterConfig.cs b/src/Mapster.Tests/WhenUseTempAdapterConfig.cs new file mode 100644 index 00000000..1def0b88 --- /dev/null +++ b/src/Mapster.Tests/WhenUseTempAdapterConfig.cs @@ -0,0 +1,75 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Shouldly; + +namespace Mapster.Tests +{ + + public record SourceDto(string Name, int Age); + public record DestinationDto(long Id, string Name, int Age); + + [TestClass] + public class WhenUseTempAdapterConfig + { + [TestMethod] + public void Adapt_TemporaryConfig_ShouldMapInitOnlyProperties() + { + // Arrange + var source = new SourceDto("Alice", 30); + long id = 42; + + // Act + var result = source.Adapt(cfg => + { + cfg.NewConfig() + .Map(dest => dest.Id, src => id); + }); + + // Assert + result.Name.ShouldBe("Alice"); + result.Age.ShouldBe(30); + result.Id.ShouldBe(42); + } + + [TestMethod] + public void Adapt_WithSetter_ShouldMapInitOnlyProperties() + { + // Arrange + var source = new SourceDto("Bob", 25); + long id = 99; + + // Act + var result = source.Adapt(setter => + { + setter.Map(dest => dest.Id, src => id); + }); + + // Assert + result.Name.ShouldBe("Bob"); + result.Age.ShouldBe(25); + result.Id.ShouldBe(99); + } + + [TestMethod] + public void Adapt_TemporaryConfig_ShouldNotModifyGlobalSettings() + { + // Arrange + var source = new SourceDto("Charlie", 40); + long id = 123; + + var globalMap = TypeAdapterConfig.GlobalSettings.GetMapFunction(); + + // Act + var result = source.Adapt(setter => + { + setter.Map(dest => dest.Id, src => id); + }); + + // Assert + var original = globalMap(source); // mapping via GlobalSettings + original.Id.ShouldBe(default(long)); // GlobalSettings unaffected + original.Name.ShouldBe("Charlie"); + original.Age.ShouldBe(40); + } + + } +} diff --git a/src/Mapster/TypeAdapter.cs b/src/Mapster/TypeAdapter.cs index 8b87b3eb..7a42ab4a 100644 --- a/src/Mapster/TypeAdapter.cs +++ b/src/Mapster/TypeAdapter.cs @@ -263,6 +263,42 @@ public static TDestination ValidateAndAdapt(this TSource } 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 = "")]