public TN Map <T, TN>(T src, TN dest = default(TN)) { var srcType = typeof(T); var destType = typeof(TN); var cacheKey = CalculateCacheKey(srcType, destType); if (CustomMappers.ContainsKey(cacheKey)) { var customTypeMapper = CustomMappers[cacheKey]; var typeMapper = customTypeMapper() as ICustomTypeMapper <T, TN>; var context = new DefaultMappingContext <T, TN> { Source = src, Destination = dest }; return(typeMapper.Map(context)); } var mappingService = EqualityComparer <TN> .Default.Equals(dest, default(TN)) ? SourceService : DestinationService; if (mappingService.TypeMappers.ContainsKey(cacheKey)) { if (EqualityComparer <T> .Default.Equals(src, default(T))) { return(default(TN)); } var mapper = mappingService.TypeMappers[cacheKey] as ITypeMapper <T, TN>; return(mapper != null ? mapper.MapTo(src, dest) : default(TN)); } var tCol = typeof(T).GetInterfaces() .FirstOrDefault(t => t.IsGenericType && t.GetGenericTypeDefinition() == GenericEnumerableType) ?? (typeof(T).IsGenericType && typeof(T).GetInterfaces().Any(t => t == typeof(IEnumerable)) ? typeof(T) : null); var tnCol = typeof(TN).GetInterfaces() .FirstOrDefault(t => t.IsGenericType && t.GetGenericTypeDefinition() == GenericEnumerableType) ?? (typeof(TN).IsGenericType && typeof(TN).GetInterfaces().Any(t => t == typeof(IEnumerable)) ? typeof(TN) : null); if (tCol == null || tnCol == null) { throw new MapNotImplementedException( string.Format("There is no mapping has bee found. Source Type: {0}, Destination Type: {1}", srcType.FullName, destType.FullName)); } PrecompileCollection <T, TN>(); // todo: make same signature in both compiled funcs with destination var result = (TN)(((EqualityComparer <TN> .Default.Equals(dest, default(TN))) ? SourceService.MapCollection(cacheKey).DynamicInvoke(src) : DestinationService.MapCollection(cacheKey).DynamicInvoke(src, dest))); return(result); }
private object MapNonGenericInternal(Type srcType, Type dstType, object src, object dest = 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)); } var mappingService = dest == null ? SourceService : DestinationService; if (mappingService.TypeMappers.ContainsKey(cacheKey)) { if (src == null) { return(null); } var mapper = mappingService.TypeMappers[cacheKey]; var nonGenericMapFunc = mapper.GetNonGenericMapFunc(); return(nonGenericMapFunc(src, dest)); } var tCol = srcType.GetInterfaces() .FirstOrDefault(t => t.IsGenericType && t.GetGenericTypeDefinition() == GenericEnumerableType) ?? (srcType.IsGenericType && srcType.GetInterfaces().Any(t => t == typeof(IEnumerable)) ? srcType : null); var tnCol = dstType.GetInterfaces() .FirstOrDefault(t => t.IsGenericType && t.GetGenericTypeDefinition() == GenericEnumerableType) ?? (dstType.IsGenericType && dstType.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); } throw new MapNotImplementedException( string.Format("There is no mapping has bee found. Source Type: {0}, Destination Type: {1}", srcType.FullName, dstType.FullName)); }
public void RegisterCustom <T, TN, TMapper>() where TMapper : ICustomTypeMapper <T, TN> { lock (_lock) { var src = typeof(T); var dest = typeof(TN); var cacheKey = CalculateCacheKey(src, dest); if (CustomMappers.ContainsKey(cacheKey)) { throw new InvalidOperationException( $"Mapping from {src.FullName} to {dest.FullName} is already registered"); } var newExpression = Expression.New(typeof(TMapper)); var newLambda = Expression.Lambda <Func <ICustomTypeMapper <T, TN> > >(newExpression); var compile = newLambda.Compile(); CustomMappers[cacheKey] = compile; } }
public void RegisterCustom <T, TN>(Func <T, TN> mapFunc) { lock (_lock) { var src = typeof(T); var dest = typeof(TN); var cacheKey = CalculateCacheKey(src, dest); if (CustomMappers.ContainsKey(cacheKey)) { throw new InvalidOperationException( $"Mapping from {src.FullName} to {dest.FullName} is already registered"); } var delegateMapperType = typeof(DelegateCustomTypeMapper <,>).MakeGenericType(src, dest); var newExpression = Expression.New( delegateMapperType.GetInfo().GetConstructor(new Type[] { typeof(Func <,>).MakeGenericType(src, dest) }), Expression.Constant(mapFunc)); var newLambda = Expression.Lambda <Func <ICustomTypeMapper <T, TN> > >(newExpression); var compile = newLambda.Compile(); CustomMappers.Add(cacheKey, compile); } }
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)); }