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; } }
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; } }
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); } } }
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); } }
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); } }
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); } }