protected void FindDestinationFullName(Type typeSource, Type typeDestination, string sourceFullName, List <PropertyMapInfo> propertyMapInfoList) { const string period = "."; bool BothTypesAreAnonymous() => IsAnonymousType(typeSource) && IsAnonymousType(typeDestination); TypeMap GetTypeMap() => BothTypesAreAnonymous() ? anonymousTypesConfigurationProvider.CheckIfTypeMapExists(sourceType: typeDestination, destinationType: typeSource) : ConfigurationProvider.CheckIfTypeMapExists(sourceType: typeDestination, destinationType: typeSource); //The destination becomes the source because to map a source expression to a destination expression, //we need the expressions used to create the source from the destination if (typeSource == typeDestination) { var sourceFullNameArray = sourceFullName.Split(new[] { period[0] }, StringSplitOptions.RemoveEmptyEntries); sourceFullNameArray.Aggregate(propertyMapInfoList, (list, next) => { if (list.Count == 0) { AddPropertyMapInfo(typeSource, next, list); } else { var last = list[list.Count - 1]; AddPropertyMapInfo(last.CustomExpression == null ? last.DestinationPropertyInfos[last.DestinationPropertyInfos.Count - 1].GetMemberType() : last.CustomExpression.ReturnType, next, list); } return(list); }); return; } if (GenericTypeDefinitionsAreEquivalent(typeSource, typeDestination)) { if (sourceFullName.IndexOf(period, StringComparison.OrdinalIgnoreCase) < 0) { //sourceFullName is a member of the generic type definition so just add the members PropertyMapInfo AddPropertyMapInfo(typeDestination, sourceFullName, propertyMapInfoList); var sourceType = typeSource.GetFieldOrProperty(sourceFullName).GetMemberType(); var destType = typeDestination.GetFieldOrProperty(sourceFullName).GetMemberType(); TypeMappings.AddTypeMapping(ConfigurationProvider, sourceType, destType); return; } else { //propertyName is a member of the generic type definition so just add the members PropertyMapInfo var propertyName = sourceFullName.Substring(0, sourceFullName.IndexOf(period, StringComparison.OrdinalIgnoreCase)); AddPropertyMapInfo(typeDestination, propertyName, propertyMapInfoList); var sourceType = typeSource.GetFieldOrProperty(propertyName).GetMemberType(); var destType = typeDestination.GetFieldOrProperty(propertyName).GetMemberType(); TypeMappings.AddTypeMapping(ConfigurationProvider, sourceType, destType); var childFullName = sourceFullName.Substring(sourceFullName.IndexOf(period, StringComparison.OrdinalIgnoreCase) + 1); FindDestinationFullName(sourceType, destType, childFullName, propertyMapInfoList); return; } } var typeMap = GetTypeMap(); PathMap pathMap = typeMap.FindPathMapByDestinationFullPath(destinationFullPath: sourceFullName); if (pathMap != null) { propertyMapInfoList.Add(new PropertyMapInfo(pathMap.CustomMapExpression, new List <MemberInfo>())); return; } if (sourceFullName.IndexOf(period, StringComparison.OrdinalIgnoreCase) < 0) { var propertyMap = typeMap.GetMemberMapByDestinationProperty(sourceFullName); var sourceMemberInfo = typeSource.GetFieldOrProperty(propertyMap.GetDestinationName()); if (propertyMap.ValueResolverConfig != null) { throw new InvalidOperationException(Resource.customResolversNotSupported); } if (propertyMap.CustomMapExpression == null && !propertyMap.SourceMembers.Any()) { throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Resource.srcMemberCannotBeNullFormat, typeSource.Name, typeDestination.Name, sourceFullName)); } // CompareSourceAndDestLiterals // ( // propertyMap.CustomMapExpression != null ? propertyMap.CustomMapExpression.ReturnType : propertyMap.SourceMember.GetMemberType(), // propertyMap.CustomMapExpression != null ? propertyMap.CustomMapExpression.ToString() : propertyMap.SourceMember.Name, // sourceMemberInfo.GetMemberType() // ); // void CompareSourceAndDestLiterals(Type mappedPropertyType, string mappedPropertyDescription, Type sourceMemberType) // { // //switch from IsValueType to IsLiteralType because we do not want to throw an exception for all structs // if ((mappedPropertyType.IsLiteralType() || sourceMemberType.IsLiteralType()) && sourceMemberType != mappedPropertyType) // throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Resource.expressionMapValueTypeMustMatchFormat, mappedPropertyType.Name, mappedPropertyDescription, sourceMemberType.Name, propertyMap.GetDestinationName())); // } if (propertyMap.IncludedMember?.ProjectToCustomSource != null) { propertyMapInfoList.Add(new PropertyMapInfo(propertyMap.IncludedMember.ProjectToCustomSource, new List <MemberInfo>())); } propertyMapInfoList.Add(new PropertyMapInfo(propertyMap.CustomMapExpression, propertyMap.SourceMembers.ToList())); } else { var propertyName = sourceFullName.Substring(0, sourceFullName.IndexOf(period, StringComparison.OrdinalIgnoreCase)); var propertyMap = typeMap.GetMemberMapByDestinationProperty(propertyName); var sourceMemberInfo = typeSource.GetFieldOrProperty(propertyMap.GetDestinationName()); if (propertyMap.CustomMapExpression == null && !propertyMap.SourceMembers.Any())//If sourceFullName has a period then the SourceMember cannot be null. The SourceMember is required to find the ProertyMap of its child object. { throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Resource.srcMemberCannotBeNullFormat, typeSource.Name, typeDestination.Name, propertyName)); } if (propertyMap.IncludedMember?.ProjectToCustomSource != null) { propertyMapInfoList.Add(new PropertyMapInfo(propertyMap.IncludedMember.ProjectToCustomSource, new List <MemberInfo>())); } propertyMapInfoList.Add(new PropertyMapInfo(propertyMap.CustomMapExpression, propertyMap.SourceMembers.ToList())); var childFullName = sourceFullName.Substring(sourceFullName.IndexOf(period, StringComparison.OrdinalIgnoreCase) + 1); FindDestinationFullName(sourceMemberInfo.GetMemberType(), propertyMap.CustomMapExpression == null ? propertyMap.SourceMember.GetMemberType() : propertyMap.CustomMapExpression.ReturnType, childFullName, propertyMapInfoList); } }