Пример #1
0
        public static void ArrayUpdate <TSourceElement, TTargetElement>(
            Mapper mapper, ReferenceTracking referenceTracker,
            IEnumerable <TSourceElement> source, TTargetElement[] target,
            Func <TSourceElement, TTargetElement, bool> comparer)
            where TSourceElement : class
            where TTargetElement : class, new()
        {
            MapItems(mapper, referenceTracker, source, target, comparer);

            var arrayTarget = target as TTargetElement[];
            var sourceCount = source.Count();

            if (sourceCount > arrayTarget.Length)
            {
                arrayTarget = target = new TTargetElement[sourceCount];
            }

            int index = 0;

            foreach (var item in source)
            {
                var targetItem = (TTargetElement)referenceTracker[item, typeof(TTargetElement)];
                target[index++] = targetItem;
            }
        }
Пример #2
0
        public static void Update <TSourceElement, TTargetElement>(
            Mapper mapper, ReferenceTracking referenceTracker,
            IEnumerable <TSourceElement> source, ICollection <TTargetElement> target,
            Func <TSourceElement, TTargetElement, bool> comparer)
            where TSourceElement : class
            where TTargetElement : class, new()
        {
            switch (target)
            {
            case TTargetElement[] array:
                ArrayUpdate(mapper, referenceTracker, source, array, comparer);
                break;

            case Queue <TTargetElement> queue:
                UpdateQueue(mapper, referenceTracker, source, queue, comparer);
                break;

            case Stack <TTargetElement> stack:
                UpdateStack(mapper, referenceTracker, source, stack, comparer);
                break;

            default:
                CollectionUpdate(mapper, referenceTracker, source, target, comparer);
                break;
            }
        }
Пример #3
0
        private static void MapItems <TSourceElement, TTargetElement>(Mapper mapper,
                                                                      ReferenceTracking referenceTracker, IEnumerable <TSourceElement> source,
                                                                      IEnumerable <TTargetElement> target, Func <TSourceElement, TTargetElement, bool> comparer)
            where TSourceElement : class
            where TTargetElement : class, new()
        {
            //search items to add, map and add them
            foreach (var sourceItem in source)
            {
                bool addToList = true;
                foreach (var targetItem in target)
                {
                    if (comparer(sourceItem, targetItem))
                    {
                        mapper.Map(sourceItem, targetItem, referenceTracker);
                        addToList = false; //we already updated
                        break;             //next source item
                    }
                }

                if (addToList)
                {
                    var targetItem = new TTargetElement();
                    mapper.Map(sourceItem, targetItem, referenceTracker);
                }
            }
        }
Пример #4
0
        public static void CollectionUpdate <TSourceElement, TTargetElement>(
            Mapper mapper, ReferenceTracking referenceTracker,
            IEnumerable <TSourceElement> source, ICollection <TTargetElement> target,
            Func <TSourceElement, TTargetElement, bool> comparer)
            where TSourceElement : class
            where TTargetElement : class, new()
        {
            MapItems(mapper, referenceTracker, source, target, comparer);

            target.Clear();
            foreach (var item in source)
            {
                var targetItem = (TTargetElement)referenceTracker[item, typeof(TTargetElement)];
                target.Add(targetItem);
            }
        }
Пример #5
0
        public static void UpdateStack <TSourceElement, TTargetElement>(
            Mapper mapper, ReferenceTracking referenceTracker,
            IEnumerable <TSourceElement> source, Stack <TTargetElement> target,
            Func <TSourceElement, TTargetElement, bool> comparer)
            where TSourceElement : class
            where TTargetElement : class, new()
        {
            MapItems(mapper, referenceTracker, source, target, comparer);

            var tempStack = new Stack <TTargetElement>();

            foreach (var item in source)
            {
                var targetItem = (TTargetElement)referenceTracker[item, typeof(TTargetElement)];
                tempStack.Push(targetItem);
            }

            target.Clear();

            foreach (var item in tempStack)
            {
                target.Push(item);
            }
        }
Пример #6
0
        private static bool VerifyMapperResultHelper(this Mapper ultraMapper,
                                                     object source, object target, ReferenceTracking referenceTracking)
        {
            //sharing the same reference or both null
            if (Object.ReferenceEquals(source, target))
            {
                return(true);
            }

            //either source or target is null
            if (source == null || target == null)
            {
                return(false);
            }

            Type sourceType = source.GetType();
            Type targetType = target.GetType();

            if (!sourceType.IsValueType && source != null)
            {
                if (referenceTracking.Contains(source, targetType))
                {
                    return(true);
                }

                if (!sourceType.IsValueType)
                {
                    referenceTracking.Add(source, targetType, target);
                }
            }

            //same value type: just compare their values
            if (sourceType == targetType && sourceType.IsBuiltInType(false))
            {
                return(source.Equals(target));
            }

            if (sourceType.IsEnumerable() && targetType.IsEnumerable())
            {
                var firstPos  = (source as IEnumerable).GetEnumerator();
                var secondPos = (target as IEnumerable).GetEnumerator();

                var hasFirst  = firstPos.MoveNext();
                var hasSecond = secondPos.MoveNext();

                while (hasFirst && hasSecond)
                {
                    if (!VerifyMapperResultHelper(ultraMapper, firstPos.Current, secondPos.Current, referenceTracking))
                    {
                        return(false);
                    }

                    hasFirst  = firstPos.MoveNext();
                    hasSecond = secondPos.MoveNext();
                }

                if (hasFirst ^ hasSecond)
                {
                    return(false);
                }
            }

            var typeMapping = ultraMapper.MappingConfiguration[
                source.GetType(), target.GetType()];

            foreach (var mapping in typeMapping.MemberMappings.Values)
            {
                if (mapping.MappingResolution == Internals.MappingResolution.RESOLVED_BY_CONVENTION &&
                    typeMapping.IgnoreMemberMappingResolvedByConvention == true)
                {
                    continue;
                }

                var sourceValue = mapping.SourceMember
                                  .ValueGetter.Compile().DynamicInvoke(source);

                var converter = mapping.CustomConverter;
                if (converter != null)
                {
                    sourceValue = converter.Compile().DynamicInvoke(sourceValue);
                }

                var targetValue = mapping.TargetMember
                                  .ValueGetter.Compile().DynamicInvoke(target);

                if (!mapping.SourceMember.MemberType.IsValueType && sourceValue != null)
                {
                    if (referenceTracking.Contains(sourceValue, mapping.TargetMember.MemberType))
                    {
                        continue;
                    }

                    var result = VerifyMapperResultHelper(ultraMapper, sourceValue, targetValue, referenceTracking);
                    if (!result)
                    {
                        return(false);
                    }

                    referenceTracking.Add(sourceValue, mapping.TargetMember.MemberType, targetValue);
                }

                if (Object.ReferenceEquals(sourceValue, targetValue))
                {
                    continue;
                }

                bool isSourcePropertyNullable = Nullable.GetUnderlyingType(mapping.SourceMember.MemberType) != null;
                bool isTargetPropertyNullable = Nullable.GetUnderlyingType(mapping.TargetMember.MemberType) != null;

                if (isSourcePropertyNullable && !isTargetPropertyNullable && sourceValue == null &&
                    targetValue.Equals(mapping.TargetMember.MemberType.GetDefaultValueViaActivator()))
                {
                    continue;
                }

                if (sourceValue == null ^ targetValue == null)
                {
                    return(false);
                }

                if (sourceValue.GetType().IsEnumerable() && targetValue.GetType().IsEnumerable())
                {
                    var firstPos  = (sourceValue as IEnumerable).GetEnumerator();
                    var secondPos = (targetValue as IEnumerable).GetEnumerator();

                    var hasFirst  = firstPos.MoveNext();
                    var hasSecond = secondPos.MoveNext();

                    while (hasFirst && hasSecond)
                    {
                        if (!VerifyMapperResultHelper(ultraMapper, firstPos.Current, secondPos.Current, referenceTracking))
                        {
                            return(false);
                        }

                        hasFirst  = firstPos.MoveNext();
                        hasSecond = secondPos.MoveNext();
                    }

                    if (hasFirst ^ hasSecond)
                    {
                        return(false);
                    }
                }

                //same value type: just compare their values
                if (sourceValue.GetType() == targetValue.GetType() && sourceValue.GetType().IsValueType)
                {
                    if (!sourceValue.Equals(targetValue))
                    {
                        return(false);
                    }
                }
            }

            return(true);
        }
        internal static void Update <TSourceElement, TTargetElement>(Mapper mapper, ReferenceTracking referenceTracker,
                                                                     IEnumerable <TSourceElement> source, ICollection <TTargetElement> target, Func <TSourceElement, TTargetElement, bool> comparer)
            where TSourceElement : class
            where TTargetElement : class, new()
        {
            //search items to remove...
            var itemsToRemove = new List <TTargetElement>();

            foreach (var targetItem in target)
            {
                bool remove = true;
                foreach (var sourceItem in source)
                {
                    if (comparer(sourceItem, targetItem))
                    {
                        remove = false;
                    }
                }

                if (remove)
                {
                    itemsToRemove.Add(targetItem);
                }
            }

            //..and remove them
            foreach (var item in itemsToRemove)
            {
                target.Remove(item);
            }

            var itemsToAdd = new List <TTargetElement>();

            //search items to add, map and add them
            foreach (var sourceItem in source)
            {
                bool addToList = true;
                foreach (var targetItem in target)
                {
                    if (comparer(sourceItem, targetItem))
                    {
                        mapper.Map(sourceItem, targetItem, referenceTracker);
                        addToList = false; //we already updated
                        break;             //next source item
                    }
                }

                if (addToList)
                {
                    var targetItem = new TTargetElement();
                    mapper.Map(sourceItem, targetItem, referenceTracker);
                    itemsToAdd.Add(targetItem);
                }
            }

            //it is important to add the items after the target collection
            //has been updated (or it can happen that we update items that only needed
            //to be added acting more or less like a hashset).
            foreach (var item in itemsToAdd)
            {
                target.Add(item);
            }
        }