예제 #1
0
        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));
        }