public void Add(DerivedTypePair typePair)
        {
            var parentType = typePair.DerivedTargetType.GetBaseType();

            while (parentType != typeof(object))
            {
                List <DerivedTypePair> typePairs;

                // ReSharper disable once AssignNullToNotNullAttribute
                if (_typePairsByTargetType.TryGetValue(parentType, out typePairs))
                {
                    RemoveConflictingPairIfAppropriate(typePair, typePairs);

                    typePairs.Add(typePair);
                    typePairs.Sort(DerivedTypePairComparer.Instance);
                }
                else
                {
                    _typePairsByTargetType[parentType] = new List <DerivedTypePair> {
                        typePair
                    };
                }

                parentType = parentType.GetBaseType();
            }
        }
        private void AddTypePairFor(Type targetType, DerivedTypePair typePair)
        {
            if (_typePairsByTargetType.TryGetValue(targetType, out var typePairs))
            {
                RemoveConflictingPairIfAppropriate(typePair, typePairs);
                typePairs.AddThenSort(typePair);
                return;
            }

            _typePairsByTargetType[targetType] = new List <DerivedTypePair> {
                typePair
            };
        }
        public void Add(DerivedTypePair typePair)
        {
            if (typePair.IsImplementationPairing)
            {
                AddTypePairFor(typePair.TargetType, typePair);
                return;
            }

            var targetType = typePair.DerivedTargetType.GetBaseType();

            while (targetType != typeof(object))
            {
                AddTypePairFor(targetType, typePair);
                targetType = targetType.GetBaseType();
            }
        }
        private static void RemoveConflictingPairIfAppropriate(
            DerivedTypePair typePair,
            IList <DerivedTypePair> typePairs)
        {
            if (typePair.HasConfiguredCondition)
            {
                return;
            }

            var existingTypePair = typePairs.FirstOrDefault(typePair.DerivedSourceType, (dst, tp) =>
                                                            !tp.HasConfiguredCondition && (tp.DerivedSourceType == dst));

            if (existingTypePair != null)
            {
                typePairs.Remove(existingTypePair);
            }
        }
        private DerivedTypePair CreatePairFor(
            Type rootSourceType,
            Type derivedSourceType,
            Type rootTargetType,
            Type derivedTargetType)
        {
            var configInfo = new MappingConfigInfo(_mapperContext)
                             .ForAllRuleSets()
                             .ForSourceType(rootSourceType)
                             .ForTargetType(rootTargetType);

            var derivedTypePair = new DerivedTypePair(
                configInfo,
                derivedSourceType,
                derivedTargetType);

            return(derivedTypePair);
        }
        private void LookForDerivedTypePairs(IBasicMapperData mapperData, MapperContext mapperContext)
        {
            var rootSourceType = GetRootType(mapperData.SourceType);
            var rootTargetType = GetRootType(mapperData.TargetType);
            var typesKey       = new SourceAndTargetTypesKey(rootSourceType, rootTargetType);

            lock (_lookupSync)
            {
                if (_autoCheckedTypes.Contains(typesKey))
                {
                    return;
                }

                _autoCheckedTypes.Add(typesKey);
            }

            if (mapperData.TargetMember.IsSimple)
            {
                mapperData = mapperData.Parent;
            }

            Func <Type, string> derivedTargetTypeNameFactory;

            if (SkipDerivedTypePairsLookup(
                    mapperData,
                    rootSourceType,
                    rootTargetType,
                    out derivedTargetTypeNameFactory))
            {
                return;
            }

            var derivedSourceTypes = mapperContext.DerivedTypes.GetTypesDerivedFrom(rootSourceType);

            if (derivedSourceTypes.None())
            {
                return;
            }

            var derivedTargetTypes = mapperContext.DerivedTypes.GetTypesDerivedFrom(rootTargetType);

            if (derivedTargetTypes.None())
            {
                return;
            }

            var candidatePairsData = derivedSourceTypes
                                     .Select(t => new
            {
                DerivedSourceType     = t,
                DerivedTargetTypeName = derivedTargetTypeNameFactory.Invoke(t)
            })
                                     .ToArray();

            foreach (var candidatePairData in candidatePairsData)
            {
                var derivedTargetType = derivedTargetTypes
                                        .FirstOrDefault(t => t.Name == candidatePairData.DerivedTargetTypeName);

                if (derivedTargetType == null)
                {
                    continue;
                }

                var configInfo = new MappingConfigInfo(mapperContext)
                                 .ForRuleSet(mapperData.RuleSet)
                                 .ForSourceType(rootSourceType)
                                 .ForTargetType(rootTargetType);

                var derivedTypePair = new DerivedTypePair(
                    configInfo,
                    candidatePairData.DerivedSourceType,
                    derivedTargetType);

                Add(derivedTypePair);
            }
        }