88
99namespace AutoMapper . Execution
1010{
11+ using AutoMapper . Mappers . Internal ;
1112 using static Expression ;
1213 using static ExpressionFactory ;
1314
@@ -501,14 +502,14 @@ public Expression MapExpression(TypePair typePair, Expression sourceParameter, P
501502
502503 public static Expression MapExpression ( IConfigurationProvider configurationProvider , ProfileMap profileMap , TypePair typePair , Expression sourceParameter , Expression contextParameter , PropertyMap propertyMap = null , Expression destinationParameter = null )
503504 {
504- if ( destinationParameter == null )
505+ if ( destinationParameter == null )
505506 {
506507 destinationParameter = Default ( typePair . DestinationType ) ;
507508 }
508509 var typeMap = configurationProvider . ResolveTypeMap ( typePair ) ;
509- if ( typeMap != null )
510+ if ( typeMap != null )
510511 {
511- if ( ! typeMap . HasDerivedTypesToInclude ( ) )
512+ if ( ! typeMap . HasDerivedTypesToInclude ( ) )
512513 {
513514 typeMap . Seal ( configurationProvider ) ;
514515
@@ -518,8 +519,56 @@ public static Expression MapExpression(IConfigurationProvider configurationProvi
518519 }
519520 return ContextMap ( typePair , sourceParameter , contextParameter , destinationParameter ) ;
520521 }
522+ var objectMapperExpression = ObjectMapperExpression ( configurationProvider , profileMap , typePair , sourceParameter , contextParameter , propertyMap , destinationParameter ) ;
523+ return NullCheckSource ( profileMap , sourceParameter , destinationParameter , objectMapperExpression ) ;
524+ }
525+
526+ public static Expression NullCheckSource ( ProfileMap profileMap , Expression sourceParameter , Expression destinationParameter , Expression objectMapperExpression )
527+ {
528+ var destinationType = destinationParameter . Type ;
529+ var defaultDestination = DefaultDestination ( destinationType , profileMap ) ;
530+ var ifSourceNull = destinationType . IsCollectionType ( ) ? Block ( ClearDestinationCollection ( destinationParameter ) , defaultDestination ) : defaultDestination ;
531+ return sourceParameter . IfNullElse ( ifSourceNull , objectMapperExpression ) ;
532+ }
533+
534+ private static Expression ClearDestinationCollection ( Expression destinationParameter )
535+ {
536+ var destinationElementType = ElementTypeHelper . GetElementType ( destinationParameter . Type ) ;
537+ var destinationCollectionType = typeof ( ICollection < > ) . MakeGenericType ( destinationElementType ) ;
538+ var clearMethod = destinationCollectionType . GetDeclaredMethod ( "Clear" ) ;
539+ var collection = ToType ( destinationParameter , destinationCollectionType ) ;
540+ var clear = Condition ( Property ( collection , "IsReadOnly" ) , Empty ( ) , Call ( collection , clearMethod ) ) ;
541+ return collection . IfNullElse ( Empty ( ) , clear ) ;
542+ }
543+
544+ private static Expression DefaultDestination ( Type destinationType , ProfileMap profileMap )
545+ {
546+ var defaultValue = Default ( destinationType ) ;
547+ if ( ! profileMap . AllowNullCollections )
548+ {
549+ if ( destinationType . IsArray )
550+ {
551+ var destinationElementType = ElementTypeHelper . GetElementType ( destinationType ) ;
552+ return NewArrayBounds ( destinationElementType , Enumerable . Repeat ( Constant ( 0 ) , destinationType . GetArrayRank ( ) ) ) ;
553+ }
554+ if ( destinationType . IsDictionaryType ( ) )
555+ {
556+ return destinationType . IsInterface ( ) ?
557+ DelegateFactory . GenerateNonNullConstructorExpression ( typeof ( Dictionary < , > ) . MakeGenericType ( destinationType . GetGenericArguments ( ) ) ) :
558+ defaultValue ;
559+ }
560+ if ( destinationType . IsCollectionType ( ) && ! destinationType . IsInterface ( ) )
561+ {
562+ return DelegateFactory . GenerateNonNullConstructorExpression ( destinationType ) ;
563+ }
564+ }
565+ return defaultValue ;
566+ }
567+
568+ private static Expression ObjectMapperExpression ( IConfigurationProvider configurationProvider , ProfileMap profileMap , TypePair typePair , Expression sourceParameter , Expression contextParameter , PropertyMap propertyMap , Expression destinationParameter )
569+ {
521570 var match = configurationProvider . GetMappers ( ) . FirstOrDefault ( m => m . IsMatch ( typePair ) ) ;
522- if ( match != null )
571+ if ( match != null )
523572 {
524573 var mapperExpression = match . MapExpression ( configurationProvider , profileMap , propertyMap , sourceParameter , destinationParameter , contextParameter ) ;
525574
0 commit comments