Skip to content

Commit 9103951

Browse files
authored
Merge pull request #828 from roohial57/development
Add Adapt extensions with temporary TypeAdapterConfig and TypeAdapter
2 parents 6a81c81 + a009eff commit 9103951

File tree

2 files changed

+111
-0
lines changed

2 files changed

+111
-0
lines changed
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
using Microsoft.VisualStudio.TestTools.UnitTesting;
2+
using Shouldly;
3+
4+
namespace Mapster.Tests
5+
{
6+
7+
public record SourceDto(string Name, int Age);
8+
public record DestinationDto(long Id, string Name, int Age);
9+
10+
[TestClass]
11+
public class WhenUseTempAdapterConfig
12+
{
13+
[TestMethod]
14+
public void Adapt_TemporaryConfig_ShouldMapInitOnlyProperties()
15+
{
16+
// Arrange
17+
var source = new SourceDto("Alice", 30);
18+
long id = 42;
19+
20+
// Act
21+
var result = source.Adapt<DestinationDto>(cfg =>
22+
{
23+
cfg.NewConfig<SourceDto, DestinationDto>()
24+
.Map(dest => dest.Id, src => id);
25+
});
26+
27+
// Assert
28+
result.Name.ShouldBe("Alice");
29+
result.Age.ShouldBe(30);
30+
result.Id.ShouldBe(42);
31+
}
32+
33+
[TestMethod]
34+
public void Adapt_WithSetter_ShouldMapInitOnlyProperties()
35+
{
36+
// Arrange
37+
var source = new SourceDto("Bob", 25);
38+
long id = 99;
39+
40+
// Act
41+
var result = source.Adapt<SourceDto, DestinationDto>(setter =>
42+
{
43+
setter.Map(dest => dest.Id, src => id);
44+
});
45+
46+
// Assert
47+
result.Name.ShouldBe("Bob");
48+
result.Age.ShouldBe(25);
49+
result.Id.ShouldBe(99);
50+
}
51+
52+
[TestMethod]
53+
public void Adapt_TemporaryConfig_ShouldNotModifyGlobalSettings()
54+
{
55+
// Arrange
56+
var source = new SourceDto("Charlie", 40);
57+
long id = 123;
58+
59+
var globalMap = TypeAdapterConfig.GlobalSettings.GetMapFunction<SourceDto, DestinationDto>();
60+
61+
// Act
62+
var result = source.Adapt<SourceDto, DestinationDto>(setter =>
63+
{
64+
setter.Map(dest => dest.Id, src => id);
65+
});
66+
67+
// Assert
68+
var original = globalMap(source); // mapping via GlobalSettings
69+
original.Id.ShouldBe(default(long)); // GlobalSettings unaffected
70+
original.Name.ShouldBe("Charlie");
71+
original.Age.ShouldBe(40);
72+
}
73+
74+
}
75+
}

src/Mapster/TypeAdapter.cs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,42 @@ public static TDestination ValidateAndAdapt<TSource, TDestination>(this TSource
263263
}
264264
return source.Adapt<TDestination>(config);
265265
}
266+
267+
268+
/// <summary>
269+
/// Adapt the source object to a destination type using a temporary configuration.
270+
/// A new TypeAdapterConfig is created for this call, ensuring GlobalSettings remain unchanged.
271+
/// Safe for init-only properties and record types.
272+
/// </summary>
273+
/// <typeparam name="TDestination">Destination type.</typeparam>
274+
/// <param name="source">Source object to adapt.</param>
275+
/// <param name="configAction">Action to customize the temporary config.</param>
276+
/// <returns>Adapted destination object of type TDestination.</returns>
277+
public static TDestination Adapt<TDestination>(this object? source, Action<TypeAdapterConfig> configAction)
278+
{
279+
var config = TypeAdapterConfig.GlobalSettings.Clone();
280+
configAction(config);
281+
return source.Adapt<TDestination>(config);
282+
}
283+
284+
/// <summary>
285+
/// Adapt the source object from TSource to TDestination using a dedicated TypeAdapterSetter.
286+
/// A temporary TypeAdapterConfig is created and configured via the setter.
287+
/// Safe for init-only properties and record types, without modifying GlobalSettings.
288+
/// </summary>
289+
/// <typeparam name="TSource">Source type.</typeparam>
290+
/// <typeparam name="TDestination">Destination type.</typeparam>
291+
/// <param name="source">Source object to adapt.</param>
292+
/// <param name="configAction">Action to customize the TypeAdapterSetter.</param>
293+
/// <returns>Adapted destination object of type TDestination.</returns>
294+
public static TDestination Adapt<TSource, TDestination>(this object? source, Action<TypeAdapterSetter<TSource, TDestination>> configAction)
295+
{
296+
var config = TypeAdapterConfig.GlobalSettings.Clone();
297+
var setter = config.ForType<TSource, TDestination>();
298+
configAction(setter);
299+
setter.Settings.Resolvers.Reverse();
300+
return source.Adapt<TDestination>(config);
301+
}
266302
}
267303

268304
[System.Diagnostics.CodeAnalysis.SuppressMessage("Minor Code Smell", "S1104:Fields should not have public accessibility", Justification = "<Pending>")]

0 commit comments

Comments
 (0)