11using System ;
2- using System . Collections . Generic ;
3- using System . Diagnostics . CodeAnalysis ;
4- using System . Linq ;
52using System . Reflection ;
6- using Mapster . Models ;
73
84namespace Mapster
95{
10- public static class TypeAdapter
6+ public static partial class TypeAdapter
117 {
12- public static ITypeAdapterBuilder < TSource > BuildAdapter < TSource > ( this TSource source )
13- {
14- return new TypeAdapterBuilder < TSource > ( source , TypeAdapterConfig . GlobalSettings ) ;
15- }
16-
17- public static ITypeAdapterBuilder < TSource > BuildAdapter < TSource > ( this TSource source , TypeAdapterConfig config )
18- {
19- return new TypeAdapterBuilder < TSource > ( source , config ) ;
20- }
21-
22- /// <summary>
23- /// Adapt the source object to the destination type.
24- /// </summary>
25- /// <typeparam name="TDestination">Destination type.</typeparam>
26- /// <param name="source">Source object to adapt.</param>
27- /// <returns>Adapted destination type.</returns>
28- [ return : NotNullIfNotNull ( nameof ( source ) ) ]
29- public static TDestination ? Adapt < TDestination > ( this object ? source )
30- {
31- return Adapt < TDestination > ( source , TypeAdapterConfig . GlobalSettings ) ;
32- }
33-
34- /// <summary>
35- /// Adapt the source object to the destination type.
36- /// </summary>
37- /// <typeparam name="TDestination">Destination type.</typeparam>
38- /// <param name="source">Source object to adapt.</param>
39- /// <param name="config">Configuration</param>
40- /// <returns>Adapted destination type.</returns>
41- [ return : NotNullIfNotNull ( nameof ( source ) ) ]
42- public static TDestination ? Adapt < TDestination > ( this object ? source , TypeAdapterConfig config )
43- {
44- // ReSharper disable once ConditionIsAlwaysTrueOrFalse
45- if ( source == null )
46- return default ;
47- var type = source . GetType ( ) ;
48- var fn = config . GetDynamicMapFunction < TDestination > ( type ) ;
49- return fn ( source ) ! ;
50- }
51-
52- /// <summary>
53- /// Adapt the source object to the destination type.
54- /// </summary>
55- /// <typeparam name="TSource">Source type.</typeparam>
56- /// <typeparam name="TDestination">Destination type.</typeparam>
57- /// <param name="source">Source object to adapt.</param>
58- /// <returns>Adapted destination type.</returns>
59- public static TDestination Adapt < TSource , TDestination > ( this TSource source )
60- {
61- return TypeAdapter < TSource , TDestination > . Map ( source ) ;
62- }
63-
64- /// <summary>
65- /// Adapt the source object to the destination type.
66- /// </summary>
67- /// <typeparam name="TSource">Source type.</typeparam>
68- /// <typeparam name="TDestination">Destination type.</typeparam>
69- /// <param name="source">Source object to adapt.</param>
70- /// <param name="config">Configuration</param>
71- /// <returns>Adapted destination type.</returns>
72- public static TDestination Adapt < TSource , TDestination > ( this TSource source , TypeAdapterConfig config )
73- {
74- var fn = config . GetMapFunction < TSource , TDestination > ( ) ;
75- return fn ( source ) ;
76- }
77-
788 /// <summary>
799 /// Adapt the source object to the existing destination object.
8010 /// </summary>
@@ -105,9 +35,9 @@ public static TDestination Adapt<TSource, TDestination>(this TSource source, TDe
10535 if ( sourceType == typeof ( object ) ) // Infinity loop in ObjectAdapter if Runtime Type of source is Object
10636 return destination ;
10737
108- if ( typeof ( TSource ) == typeof ( object ) || typeof ( TDestination ) == typeof ( object ) )
38+ if ( typeof ( TSource ) == typeof ( object ) || typeof ( TDestination ) == typeof ( object ) )
10939 return UpdateFuncFromPackedinObject ( source , destination , config , sourceType , destinationType ) ;
110-
40+
11141 var fn = config . GetMapToTargetFunction < TSource , TDestination > ( ) ;
11242 return fn ( source , destination ) ;
11343 }
@@ -130,48 +60,6 @@ private static TDestination UpdateFuncFromPackedinObject<TSource, TDestination>(
13060 }
13161 }
13262
133- /// <summary>
134- /// Adapt the source object to the destination type.
135- /// </summary>
136- /// <param name="source">Source object to adapt.</param>
137- /// <param name="sourceType">The type of the source object.</param>
138- /// <param name="destinationType">The type of the destination object.</param>
139- /// <returns>Adapted destination type.</returns>
140- public static object ? Adapt ( this object source , Type sourceType , Type destinationType )
141- {
142- if ( source != null &&
143- sourceType . IsOpenGenericType ( ) && destinationType . IsOpenGenericType ( ) )
144- {
145- var arg = source . GetType ( ) . GetGenericArguments ( ) ;
146- return Adapt ( source , sourceType . MakeGenericType ( arg ) , destinationType . MakeGenericType ( arg ) , TypeAdapterConfig . GlobalSettings ) ;
147- }
148- return Adapt ( source , sourceType , destinationType , TypeAdapterConfig . GlobalSettings ) ;
149- }
150-
151- /// <summary>
152- /// Adapt the source object to the destination type.
153- /// </summary>
154- /// <param name="source">Source object to adapt.</param>
155- /// <param name="sourceType">The type of the source object.</param>
156- /// <param name="destinationType">The type of the destination object.</param>
157- /// <param name="config">Configuration</param>
158- /// <returns>Adapted destination type.</returns>
159- public static object ? Adapt ( this object source , Type sourceType , Type destinationType , TypeAdapterConfig config )
160- {
161- var del = config . GetMapFunction ( sourceType , destinationType ) ;
162- if ( sourceType . GetTypeInfo ( ) . IsVisible && destinationType . GetTypeInfo ( ) . IsVisible )
163- {
164- dynamic fn = del ;
165- return fn ( ( dynamic ) source ) ;
166- }
167- else
168- {
169- //NOTE: if type is non-public, we cannot use dynamic
170- //DynamicInvoke is slow, but works with non-public
171- return del . DynamicInvoke ( source ) ;
172- }
173- }
174-
17563 /// <summary>
17664 /// Adapt the source object to an existing destination object.
17765 /// </summary>
@@ -209,101 +97,6 @@ private static TDestination UpdateFuncFromPackedinObject<TSource, TDestination>(
20997 return del . DynamicInvoke ( source , destination ) ;
21098 }
21199 }
212-
213- /// <summary>
214- /// Validate properties and Adapt the source object to the destination type.
215- /// </summary>
216- /// <typeparam name="TSource">Source type.</typeparam>
217- /// <typeparam name="TDestination">Destination type.</typeparam>
218- /// <param name="source">Source object to adapt.</param>
219- /// <returns>Adapted destination type.</returns>
220- public static TDestination ValidateAndAdapt < TSource , TDestination > ( this TSource source )
221- {
222- var sourceType = typeof ( TSource ) ;
223- var selectorType = typeof ( TDestination ) ;
224-
225- var sourceProperties = new HashSet < string > ( sourceType . GetProperties ( ) . Select ( p => p . Name ) ) ;
226- var selectorProperties = new HashSet < string > ( selectorType . GetProperties ( ) . Select ( p=> p . Name ) ) ;
227-
228- foreach ( var selectorProperty in selectorProperties )
229- {
230- if ( sourceProperties . Contains ( selectorProperty ) ) continue ;
231- throw new Exception ( $ "Property { selectorProperty } does not exist in { sourceType . Name } and is not configured in Mapster") ;
232- }
233- return source . Adapt < TDestination > ( ) ;
234- }
235-
236- /// <summary>
237- /// Validate properties with configuration and Adapt the source object to the destination type.
238- /// </summary>
239- /// <typeparam name="TSource">Source type.</typeparam>
240- /// <typeparam name="TDestination">Destination type.</typeparam>
241- /// <param name="source">Source object to adapt.</param>
242- /// <param name="config">Configuration</param>
243- /// <returns>Adapted destination type.</returns>
244- public static TDestination ValidateAndAdapt < TSource , TDestination > ( this TSource source , TypeAdapterConfig config )
245- {
246- var sourceType = typeof ( TSource ) ;
247- var selectorType = typeof ( TDestination ) ;
248-
249- var sourceProperties = new HashSet < string > ( sourceType . GetProperties ( ) . Select ( p => p . Name ) ) ;
250- var selectorProperties = new HashSet < string > ( selectorType . GetProperties ( ) . Select ( p=> p . Name ) ) ;
251-
252- // Get the rule map for the current types
253- var ruleMap = config . RuleMap ;
254- var typeTuple = new TypeTuple ( sourceType , selectorType ) ;
255- ruleMap . TryGetValue ( typeTuple , out var rule ) ;
256-
257- foreach ( var selectorProperty in selectorProperties )
258- {
259- if ( sourceProperties . Contains ( selectorProperty ) ) continue ;
260- // Check whether the adapter config has a config for the property
261- if ( rule != null && rule . Settings . Resolvers . Any ( r => r . DestinationMemberName . Equals ( selectorProperty ) ) ) continue ;
262- throw new Exception ( $ "Property { selectorProperty } does not exist in { sourceType . Name } and is not configured in Mapster") ;
263- }
264- return source . Adapt < TDestination > ( config ) ;
265- }
266-
267100
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- }
302- }
303-
304- [ System . Diagnostics . CodeAnalysis . SuppressMessage ( "Minor Code Smell" , "S1104:Fields should not have public accessibility" , Justification = "<Pending>" ) ]
305- public static class TypeAdapter < TSource , TDestination >
306- {
307- public static Func < TSource , TDestination > Map = TypeAdapterConfig . GlobalSettings . GetMapFunction < TSource , TDestination > ( ) ;
308101 }
309102}
0 commit comments