in tools/AutoMapper/XpressionMapper/XpressionMapperVisitor.cs [192:265]
protected void FindDestinationFullName(Type typeSource, Type typeDestination, string sourceFullName, List<PropertyMapInfo> propertyMapInfoList)
{
const string period = ".";
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;
}
var typeMap = ConfigurationProvider.CheckIfMapExists(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
PathMap pathMap = typeMap.FindPathMapByDestinationPath(destinationFullPath: sourceFullName);
if (pathMap != null)
{
propertyMapInfoList.Add(new PropertyMapInfo(pathMap.SourceExpression, new List<MemberInfo>()));
return;
}
if (sourceFullName.IndexOf(period, StringComparison.OrdinalIgnoreCase) < 0)
{
var propertyMap = typeMap.GetPropertyMapByDestinationProperty(sourceFullName);
var sourceMemberInfo = typeSource.GetFieldOrProperty(propertyMap.DestinationProperty.Name);
if (propertyMap.ValueResolverConfig != null)
{
throw new InvalidOperationException(Resource.customResolversNotSupported);
}
if (propertyMap.CustomExpression != null)
{
if (propertyMap.CustomExpression.ReturnType.IsValueType() && sourceMemberInfo.GetMemberType() != propertyMap.CustomExpression.ReturnType)
throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Resource.expressionMapValueTypeMustMatchFormat, propertyMap.CustomExpression.ReturnType.Name, propertyMap.CustomExpression.ToString(), sourceMemberInfo.GetMemberType().Name, propertyMap.DestinationProperty.Name));
}
else
{
if (propertyMap.SourceMember.GetMemberType().IsValueType() && sourceMemberInfo.GetMemberType() != propertyMap.SourceMember.GetMemberType())
throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Resource.expressionMapValueTypeMustMatchFormat, propertyMap.SourceMember.GetMemberType().Name, propertyMap.SourceMember.Name, sourceMemberInfo.GetMemberType().Name, propertyMap.DestinationProperty.Name));
}
propertyMapInfoList.Add(new PropertyMapInfo(propertyMap.CustomExpression, propertyMap.SourceMembers.ToList()));
}
else
{
var propertyName = sourceFullName.Substring(0, sourceFullName.IndexOf(period, StringComparison.OrdinalIgnoreCase));
var propertyMap = typeMap.GetPropertyMapByDestinationProperty(propertyName);
var sourceMemberInfo = typeSource.GetFieldOrProperty(propertyMap.DestinationProperty.Name);
if (propertyMap.CustomExpression == null && propertyMap.SourceMember == null)//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));
propertyMapInfoList.Add(new PropertyMapInfo(propertyMap.CustomExpression, propertyMap.SourceMembers.ToList()));
var childFullName = sourceFullName.Substring(sourceFullName.IndexOf(period, StringComparison.OrdinalIgnoreCase) + 1);
FindDestinationFullName(sourceMemberInfo.GetMemberType(), propertyMap.CustomExpression == null
? propertyMap.SourceMember.GetMemberType()
: propertyMap.CustomExpression.ReturnType, childFullName, propertyMapInfoList);
}
}