private IMemberConfiguration <T, TN> RegisterInternal <T, TN>(bool memberCaseInsensitive = true) { lock (_lock) { var src = typeof(T); var dest = typeof(TN); var cacheKey = CalculateCacheKey(src, dest); if (SourceService.TypeMappers.ContainsKey(cacheKey) && DestinationService.TypeMappers.ContainsKey(cacheKey)) { var typeMapper = SourceService.TypeMappers[cacheKey] as ITypeMapper <T, TN>; return(typeMapper?.MemberConfiguration); } if (src.GetInfo().GetInterfaces().Any(t => t.Name.Contains(typeof(IEnumerable).Name)) && dest.GetInfo().GetInterfaces().Any(t => t.Name.Contains(typeof(IEnumerable).Name))) { throw new InvalidOperationException( $"It is invalid to register mapping for collection types from {src.FullName} to {dest.FullName}, please use just class registration mapping and your collections will be implicitly processed. In case you want to include some custom collection mapping please use: Mapper.RegisterCustom."); } var sourceClassMapper = new SourceTypeMapper <T, TN>(SourceService, this); var destinationClassMapper = new DestinationTypeMapper <T, TN>(DestinationService, this); SourceService.TypeMappers[cacheKey] = sourceClassMapper; DestinationService.TypeMappers[cacheKey] = destinationClassMapper; var memberConfiguration = new MemberConfiguration <T, TN>( new ITypeMapper <T, TN>[] { sourceClassMapper, destinationClassMapper }, this); sourceClassMapper.MemberConfiguration = memberConfiguration; destinationClassMapper.MemberConfiguration = memberConfiguration; if (!CustomMappingsBySource.ContainsKey(src.GetHashCode())) { CustomMappingsBySource[src.GetHashCode()] = new List <long>(); } if (!CustomMappingsBySource[src.GetHashCode()].Contains(cacheKey)) { CustomMappingsBySource[src.GetHashCode()].Add(cacheKey); } return(memberConfiguration); } }
private object MapNonGenericInternal(Type srcType, Type dstType, object src, object dest = null, bool dynamicTrial = false) { if (src == null) { return(null); } var cacheKey = CalculateCacheKey(srcType, dstType); if (CustomMappers.ContainsKey(cacheKey)) { var customTypeMapper = CustomMappers[cacheKey]; var typeMapper = customTypeMapper(); if (!_customTypeMapperCache.ContainsKey(cacheKey)) { CompileNonGenericCustomTypeMapper(srcType, dstType, typeMapper, cacheKey); } return(_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 (CustomMappingsBySource.ContainsKey(srcHash)) { var mappings = CustomMappingsBySource[srcHash]; mapper = mappings.Where(m => DestinationService.TypeMappers.ContainsKey(m)) .Select(m => DestinationService.TypeMappers[m]) .FirstOrDefault(tm => tm.DestinationType == actualDstType); } } else { if (CustomMappingsBySource.ContainsKey(srcHash)) { var mappings = CustomMappingsBySource[srcHash]; var typeMappers = mappings.Where(m => SourceService.TypeMappers.ContainsKey(m)) .Select(m => 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 ? SourceService : 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) { CompileNonGenericCollectionMapping(srcType, dstType); // todo: make same signature in both compiled funcs with destination var result = (dest == null ? _mappingServices.First(m => !m.DestinationSupport).MapCollection(cacheKey).DynamicInvoke(src) : _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(MapNonGenericInternal(srcType, dstType, src, dest, true)); }