private object MapNonGenericInternal(Type srcType, Type dstType, object src, object dest = null, bool dynamicTrial = false) { if (src == null) { return(null); } var cacheKey = this.CalculateCacheKey(srcType, dstType); if (this.CustomMappers.ContainsKey(cacheKey)) { var customTypeMapper = this.CustomMappers[cacheKey]; var typeMapper = customTypeMapper(); if (!this._customTypeMapperCache.ContainsKey(cacheKey)) { this.CompileNonGenericCustomTypeMapper(srcType, dstType, typeMapper, cacheKey); } return(this._customTypeMapperCache[cacheKey](src, dest)); } ITypeMapper mapper = null; var actualSrcType = src.GetType(); if (srcType != actualSrcType && actualSrcType.GetInfo().IsAssignableFrom(srcType)) { throw new InvalidCastException($"Your source object instance type '{actualSrcType.FullName}' is not assignable from source type you specified '{srcType}'."); } var srcHash = actualSrcType.GetHashCode(); if (dest != null) { var actualDstType = dest.GetType(); if (dstType != actualDstType && actualDstType.GetInfo().IsAssignableFrom(dstType)) { throw new InvalidCastException($"Your destination object instance type '{actualSrcType.FullName}' is not assignable from destination type you specified '{srcType}'."); } if (this.CustomMappingsBySource.ContainsKey(srcHash)) { var mappings = this.CustomMappingsBySource[srcHash]; mapper = mappings.Where(m => this.DestinationService.TypeMappers.ContainsKey(m)) .Select(m => this.DestinationService.TypeMappers[m]) .FirstOrDefault(tm => tm.DestinationType == actualDstType); } } else { if (this.CustomMappingsBySource.ContainsKey(srcHash)) { var mappings = this.CustomMappingsBySource[srcHash]; var typeMappers = mappings.Where(m => this.SourceService.TypeMappers.ContainsKey(m)) .Select(m => this.SourceService.TypeMappers[m]) .Where(m => dstType.GetInfo().IsAssignableFrom(m.DestinationType)) .ToList(); if (typeMappers.Count > 1) { if (typeMappers.All(tm => tm.DestinationType != dstType)) { throw new AmbiguousMatchException( $"Source '{actualSrcType.FullName}' has more than one destination types' mappings"); } mapper = typeMappers.FirstOrDefault(tm => tm.DestinationType == dstType); } else { mapper = typeMappers.First(); } } } var mappingService = dest == null ? this.SourceService : this.DestinationService; if (mapper != null) { var nonGenericMapFunc = mapper.GetNonGenericMapFunc(); return(nonGenericMapFunc(src, dest)); } if (mappingService.TypeMappers.ContainsKey(cacheKey)) { mapper = mappingService.TypeMappers[cacheKey]; var nonGenericMapFunc = mapper.GetNonGenericMapFunc(); return(nonGenericMapFunc(src, dest)); } var tCol = srcType.GetInfo().GetInterfaces() .FirstOrDefault(t => t.GetInfo().IsGenericType&& t.GetGenericTypeDefinition() == GenericEnumerableType) ?? (srcType.GetInfo().IsGenericType && srcType.GetInfo().GetInterfaces().Any(t => t == typeof(IEnumerable)) ? srcType : null); var tnCol = dstType.GetInfo().GetInterfaces() .FirstOrDefault(t => t.GetInfo().IsGenericType&& t.GetGenericTypeDefinition() == GenericEnumerableType) ?? (dstType.GetInfo().IsGenericType&& dstType.GetInfo().GetInterfaces().Any(t => t == typeof(IEnumerable)) ? dstType : null); if (tCol != null && tnCol != null) { this.CompileNonGenericCollectionMapping(srcType, dstType); // todo: make same signature in both compiled funcs with destination var result = dest == null ? this._mappingServices.First(m => !m.DestinationSupport).MapCollection(cacheKey) .DynamicInvoke(src) : this._mappingServices.First(m => m.DestinationSupport).MapCollection(cacheKey) .DynamicInvoke(src, dest); return(result); } if (dynamicTrial) { throw new MapNotImplementedException( $"There is no mapping has been found. Source Type: {srcType.FullName}, Destination Type: {dstType.FullName}"); } dynamic source = src; dynamic destination = dest; Register(source, destination); return(this.MapNonGenericInternal(srcType, dstType, src, dest, true)); }