@@ -150,6 +150,19 @@ void Seal()
150150 }
151151 _features . Seal ( this ) ;
152152 }
153+ void GetDerivedTypeMaps ( TypeMap typeMap , List < TypeMap > typeMaps )
154+ {
155+ foreach ( var derivedMap in this . Internal ( ) . GetIncludedTypeMaps ( typeMap ) )
156+ {
157+ typeMaps . Add ( derivedMap ) ;
158+ GetDerivedTypeMaps ( derivedMap , typeMaps ) ;
159+ }
160+ }
161+ Delegate CompileExecutionPlan ( MapRequest mapRequest )
162+ {
163+ var executionPlan = ( ( IGlobalConfiguration ) this ) . BuildExecutionPlan ( mapRequest ) ;
164+ return executionPlan . Compile ( ) ; // breakpoint here to inspect all execution plans
165+ }
153166 }
154167 public MapperConfiguration ( Action < IMapperConfigurationExpression > configure )
155168 : this ( Build ( configure ) )
@@ -179,15 +192,62 @@ LambdaExpression IGlobalConfiguration.BuildExecutionPlan(in MapRequest mapReques
179192 }
180193 var mapperToUse = FindMapper ( mapRequest . RuntimeTypes ) ;
181194 return GenerateObjectMapperExpression ( mapRequest , mapperToUse ) ;
195+ static LambdaExpression GenerateTypeMapExpression ( TypePair requestedTypes , TypeMap typeMap )
196+ {
197+ typeMap . CheckProjection ( ) ;
198+ if ( requestedTypes == typeMap . Types )
199+ {
200+ return typeMap . MapExpression ;
201+ }
202+ var mapDestinationType = typeMap . DestinationType ;
203+ var requestedDestinationType = requestedTypes . DestinationType ;
204+ var source = Parameter ( requestedTypes . SourceType , "source" ) ;
205+ var destination = Parameter ( requestedDestinationType , "typeMapDestination" ) ;
206+ var checkNullValueTypeDest = CheckNullValueType ( destination , mapDestinationType ) ;
207+ return
208+ Lambda (
209+ ToType (
210+ Invoke ( typeMap . MapExpression , ToType ( source , typeMap . SourceType ) , ToType ( checkNullValueTypeDest , mapDestinationType ) , ContextParameter ) ,
211+ requestedDestinationType ) ,
212+ source , destination , ContextParameter ) ;
213+ }
214+ static Expression CheckNullValueType ( Expression expression , Type runtimeType ) =>
215+ ! expression . Type . IsValueType && runtimeType . IsValueType ? Coalesce ( expression , Default ( runtimeType ) ) : expression ;
216+ LambdaExpression GenerateObjectMapperExpression ( in MapRequest mapRequest , IObjectMapper mapperToUse )
217+ {
218+ var source = Parameter ( mapRequest . RequestedTypes . SourceType , "source" ) ;
219+ var destination = Parameter ( mapRequest . RequestedTypes . DestinationType , "mapperDestination" ) ;
220+ var runtimeDestinationType = mapRequest . RuntimeTypes . DestinationType ;
221+ Expression fullExpression ;
222+ if ( mapperToUse == null )
223+ {
224+ var exception = new AutoMapperMappingException ( "Missing type map configuration or unsupported mapping." , null , mapRequest . RuntimeTypes )
225+ {
226+ MemberMap = mapRequest . MemberMap
227+ } ;
228+ fullExpression = Throw ( Constant ( exception ) , runtimeDestinationType ) ;
229+ }
230+ else
231+ {
232+ var checkNullValueTypeDest = CheckNullValueType ( destination , runtimeDestinationType ) ;
233+ var map = mapperToUse . MapExpression ( this , Configuration , mapRequest . MemberMap ,
234+ ToType ( source , mapRequest . RuntimeTypes . SourceType ) ,
235+ ToType ( checkNullValueTypeDest , runtimeDestinationType ) ) ;
236+ var newException = Call ( MappingError , ExceptionParameter , Constant ( mapRequest ) ) ;
237+ var throwExpression = Throw ( newException , runtimeDestinationType ) ;
238+ fullExpression = TryCatch ( ToType ( map , runtimeDestinationType ) , Catch ( ExceptionParameter , throwExpression ) ) ;
239+ }
240+ var profileMap = mapRequest . MemberMap ? . Profile ?? Configuration ;
241+ var nullCheckSource = NullCheckSource ( profileMap , source , destination , fullExpression , mapRequest . MemberMap ) ;
242+ return Lambda ( nullCheckSource , source , destination , ContextParameter ) ;
243+ }
182244 }
183-
184- private static MapperConfigurationExpression Build ( Action < IMapperConfigurationExpression > configure )
245+ static MapperConfigurationExpression Build ( Action < IMapperConfigurationExpression > configure )
185246 {
186247 var expr = new MapperConfigurationExpression ( ) ;
187248 configure ( expr ) ;
188249 return expr ;
189250 }
190-
191251 IProjectionBuilder IGlobalConfiguration . ProjectionBuilder => _projectionBuilder ;
192252 Func < Type , object > IGlobalConfiguration . ServiceCtor => _serviceCtor ;
193253 bool IGlobalConfiguration . EnableNullPropagationForQueryMapping => _enableNullPropagationForQueryMapping ;
@@ -199,15 +259,7 @@ private static MapperConfigurationExpression Build(Action<IMapperConfigurationEx
199259 Features < IRuntimeFeature > IGlobalConfiguration . Features => _features ;
200260 Func < TSource , TDestination , ResolutionContext , TDestination > IGlobalConfiguration . GetExecutionPlan < TSource , TDestination > ( in MapRequest mapRequest )
201261 => ( Func < TSource , TDestination , ResolutionContext , TDestination > ) GetExecutionPlan ( mapRequest ) ;
202-
203262 private Delegate GetExecutionPlan ( in MapRequest mapRequest ) => _executionPlans . GetOrAdd ( mapRequest ) ;
204-
205- private Delegate CompileExecutionPlan ( MapRequest mapRequest )
206- {
207- var executionPlan = ( ( IGlobalConfiguration ) this ) . BuildExecutionPlan ( mapRequest ) ;
208- return executionPlan . Compile ( ) ; // breakpoint here to inspect all execution plans
209- }
210-
211263 TypeMap IGlobalConfiguration . ResolveAssociatedTypeMap ( TypePair types )
212264 {
213265 var typeMap = ResolveTypeMap ( types ) ;
@@ -221,56 +273,6 @@ TypeMap IGlobalConfiguration.ResolveAssociatedTypeMap(TypePair types)
221273 }
222274 return null ;
223275 }
224-
225- private static LambdaExpression GenerateTypeMapExpression ( TypePair requestedTypes , TypeMap typeMap )
226- {
227- typeMap . CheckProjection ( ) ;
228- if ( requestedTypes == typeMap . Types )
229- {
230- return typeMap . MapExpression ;
231- }
232- var mapDestinationType = typeMap . DestinationType ;
233- var requestedDestinationType = requestedTypes . DestinationType ;
234- var source = Parameter ( requestedTypes . SourceType , "source" ) ;
235- var destination = Parameter ( requestedDestinationType , "typeMapDestination" ) ;
236- var checkNullValueTypeDest = CheckNullValueType ( destination , mapDestinationType ) ;
237- return
238- Lambda (
239- ToType (
240- Invoke ( typeMap . MapExpression , ToType ( source , typeMap . SourceType ) , ToType ( checkNullValueTypeDest , mapDestinationType ) , ContextParameter ) ,
241- requestedDestinationType ) ,
242- source , destination , ContextParameter ) ;
243- }
244- private static Expression CheckNullValueType ( Expression expression , Type runtimeType ) =>
245- ! expression . Type . IsValueType && runtimeType . IsValueType ? Coalesce ( expression , Default ( runtimeType ) ) : expression ;
246- private LambdaExpression GenerateObjectMapperExpression ( in MapRequest mapRequest , IObjectMapper mapperToUse )
247- {
248- var source = Parameter ( mapRequest . RequestedTypes . SourceType , "source" ) ;
249- var destination = Parameter ( mapRequest . RequestedTypes . DestinationType , "mapperDestination" ) ;
250- var runtimeDestinationType = mapRequest . RuntimeTypes . DestinationType ;
251- Expression fullExpression ;
252- if ( mapperToUse == null )
253- {
254- var exception = new AutoMapperMappingException ( "Missing type map configuration or unsupported mapping." , null , mapRequest . RuntimeTypes )
255- {
256- MemberMap = mapRequest . MemberMap
257- } ;
258- fullExpression = Throw ( Constant ( exception ) , runtimeDestinationType ) ;
259- }
260- else
261- {
262- var checkNullValueTypeDest = CheckNullValueType ( destination , runtimeDestinationType ) ;
263- var map = mapperToUse . MapExpression ( this , Configuration , mapRequest . MemberMap ,
264- ToType ( source , mapRequest . RuntimeTypes . SourceType ) ,
265- ToType ( checkNullValueTypeDest , runtimeDestinationType ) ) ;
266- var newException = Call ( MappingError , ExceptionParameter , Constant ( mapRequest ) ) ;
267- var throwExpression = Throw ( newException , runtimeDestinationType ) ;
268- fullExpression = TryCatch ( ToType ( map , runtimeDestinationType ) , Catch ( ExceptionParameter , throwExpression ) ) ;
269- }
270- var profileMap = mapRequest . MemberMap ? . Profile ?? Configuration ;
271- var nullCheckSource = NullCheckSource ( profileMap , source , destination , fullExpression , mapRequest . MemberMap ) ;
272- return Lambda ( nullCheckSource , source , destination , ContextParameter ) ;
273- }
274276 public static AutoMapperMappingException GetMappingError ( Exception innerException , in MapRequest mapRequest ) =>
275277 new ( "Error mapping types." , innerException , mapRequest . RuntimeTypes ) { MemberMap = mapRequest . MemberMap } ;
276278 IReadOnlyCollection < TypeMap > IGlobalConfiguration . GetAllTypeMaps ( ) => _configuredMaps . Values ;
@@ -340,42 +342,78 @@ private TypeMap GetTypeMap(TypePair initialTypes)
340342 }
341343 }
342344 return null ;
343- }
344- static List < Type > GetTypeInheritance ( Type type )
345- {
346- var interfaces = type . GetInterfaces ( ) ;
347- var lastIndex = interfaces . Length - 1 ;
348- var types = new List < Type > ( interfaces . Length + 2 ) { type } ;
349- Type baseType = type ;
350- while ( ( baseType = baseType . BaseType ) != null )
345+ static List < Type > GetTypeInheritance ( Type type )
351346 {
352- types . Add ( baseType ) ;
353- foreach ( var interfaceType in baseType . GetInterfaces ( ) )
347+ var interfaces = type . GetInterfaces ( ) ;
348+ var lastIndex = interfaces . Length - 1 ;
349+ var types = new List < Type > ( interfaces . Length + 2 ) { type } ;
350+ Type baseType = type ;
351+ while ( ( baseType = baseType . BaseType ) != null )
354352 {
355- var interfaceIndex = Array . LastIndexOf ( interfaces , interfaceType ) ;
356- if ( interfaceIndex != lastIndex )
353+ types . Add ( baseType ) ;
354+ foreach ( var interfaceType in baseType . GetInterfaces ( ) )
357355 {
358- interfaces [ interfaceIndex ] = interfaces [ lastIndex ] ;
359- interfaces [ lastIndex ] = interfaceType ;
356+ var interfaceIndex = Array . LastIndexOf ( interfaces , interfaceType ) ;
357+ if ( interfaceIndex != lastIndex )
358+ {
359+ interfaces [ interfaceIndex ] = interfaces [ lastIndex ] ;
360+ interfaces [ lastIndex ] = interfaceType ;
361+ }
360362 }
361363 }
364+ foreach ( var interfaceType in interfaces )
365+ {
366+ types . Add ( interfaceType ) ;
367+ }
368+ return types ;
362369 }
363- foreach ( var interfaceType in interfaces )
370+ TypeMap FindClosedGenericTypeMapFor ( TypePair typePair )
364371 {
365- types . Add ( interfaceType ) ;
372+ if ( ! _hasOpenMaps || ! typePair . IsConstructedGenericType )
373+ {
374+ return null ;
375+ }
376+ return FindClosedGenericMap ( typePair ) ;
377+ TypeMap FindClosedGenericMap ( TypePair typePair )
378+ {
379+ var genericTypePair = typePair . GetTypeDefinitionIfGeneric ( ) ;
380+ var userMap =
381+ FindTypeMapFor ( genericTypePair . SourceType , typePair . DestinationType ) ??
382+ FindTypeMapFor ( typePair . SourceType , genericTypePair . DestinationType ) ??
383+ FindTypeMapFor ( genericTypePair ) ;
384+ ITypeMapConfiguration genericMapConfig ;
385+ ProfileMap profile ;
386+ TypeMap cachedMap ;
387+ TypePair closedTypes ;
388+ if ( userMap != null && userMap . DestinationTypeOverride == null )
389+ {
390+ genericMapConfig = userMap . Profile . GetGenericMap ( userMap . Types ) ;
391+ profile = userMap . Profile ;
392+ cachedMap = null ;
393+ closedTypes = typePair ;
394+ }
395+ else
396+ {
397+ var foundGenericMap = _resolvedMaps . TryGetValue ( genericTypePair , out cachedMap ) && cachedMap . Types . ContainsGenericParameters ;
398+ if ( ! foundGenericMap )
399+ {
400+ return cachedMap ;
401+ }
402+ genericMapConfig = cachedMap . Profile . GetGenericMap ( cachedMap . Types ) ;
403+ profile = cachedMap . Profile ;
404+ closedTypes = cachedMap . Types . CloseGenericTypes ( typePair ) ;
405+ }
406+ if ( genericMapConfig == null )
407+ {
408+ return null ;
409+ }
410+ var typeMap = profile . CreateClosedGenericTypeMap ( genericMapConfig , closedTypes , this ) ;
411+ cachedMap ? . CopyInheritedMapsTo ( typeMap ) ;
412+ return typeMap ;
413+ }
366414 }
367- return types ;
368415 }
369416 IEnumerable < IObjectMapper > IGlobalConfiguration . GetMappers ( ) => _mappers ;
370- private void GetDerivedTypeMaps ( TypeMap typeMap , List < TypeMap > typeMaps )
371- {
372- foreach ( var derivedMap in this . Internal ( ) . GetIncludedTypeMaps ( typeMap ) )
373- {
374- typeMaps . Add ( derivedMap ) ;
375- GetDerivedTypeMaps ( derivedMap , typeMaps ) ;
376- }
377- }
378-
379417 TypeMap [ ] IGlobalConfiguration . GetIncludedTypeMaps ( IReadOnlyCollection < TypePair > includedTypes )
380418 {
381419 if ( includedTypes . Count == 0 )
@@ -411,51 +449,6 @@ TypeMap GetIncludedTypeMap(TypePair pair)
411449 return typeMap ;
412450 }
413451 }
414- private TypeMap FindClosedGenericTypeMapFor ( TypePair typePair )
415- {
416- if ( ! _hasOpenMaps || ! typePair . IsConstructedGenericType )
417- {
418- return null ;
419- }
420- return FindClosedGenericMap ( typePair ) ;
421- TypeMap FindClosedGenericMap ( TypePair typePair )
422- {
423- var genericTypePair = typePair . GetTypeDefinitionIfGeneric ( ) ;
424- var userMap =
425- FindTypeMapFor ( genericTypePair . SourceType , typePair . DestinationType ) ??
426- FindTypeMapFor ( typePair . SourceType , genericTypePair . DestinationType ) ??
427- FindTypeMapFor ( genericTypePair ) ;
428- ITypeMapConfiguration genericMapConfig ;
429- ProfileMap profile ;
430- TypeMap cachedMap ;
431- TypePair closedTypes ;
432- if ( userMap != null && userMap . DestinationTypeOverride == null )
433- {
434- genericMapConfig = userMap . Profile . GetGenericMap ( userMap . Types ) ;
435- profile = userMap . Profile ;
436- cachedMap = null ;
437- closedTypes = typePair ;
438- }
439- else
440- {
441- var foundGenericMap = _resolvedMaps . TryGetValue ( genericTypePair , out cachedMap ) && cachedMap . Types . ContainsGenericParameters ;
442- if ( ! foundGenericMap )
443- {
444- return cachedMap ;
445- }
446- genericMapConfig = cachedMap . Profile . GetGenericMap ( cachedMap . Types ) ;
447- profile = cachedMap . Profile ;
448- closedTypes = cachedMap . Types . CloseGenericTypes ( typePair ) ;
449- }
450- if ( genericMapConfig == null )
451- {
452- return null ;
453- }
454- var typeMap = profile . CreateClosedGenericTypeMap ( genericMapConfig , closedTypes , this ) ;
455- cachedMap ? . CopyInheritedMapsTo ( typeMap ) ;
456- return typeMap ;
457- }
458- }
459452 IObjectMapper IGlobalConfiguration . FindMapper ( TypePair types ) => FindMapper ( types ) ;
460453 IObjectMapper FindMapper ( TypePair types )
461454 {
0 commit comments