Beispiel #1
0
        private IChangeSet <T> ProcessImpl(IChangeSet <T> changes)
        {
            changes.ForEach(change =>
            {
                switch (change.Reason)
                {
                case ListChangeReason.Add:
                    {
                        var current = change.Item.Current;
                        Insert(current);
                        break;
                    }

                case ListChangeReason.AddRange:
                    {
                        var ordered = change.Range.OrderBy(t => t, _comparer).ToList();
                        if (_innerList.Count == 0)
                        {
                            _innerList.AddRange(ordered);
                        }
                        else
                        {
                            ordered.ForEach(Insert);
                        }
                        break;
                    }

                case ListChangeReason.Replace:
                    {
                        var current = change.Item.Current;
                        //TODO: check whether an item should stay in the same position
                        //i.e. update and move
                        Remove(change.Item.Previous.Value);
                        Insert(current);
                        break;
                    }

                case ListChangeReason.Remove:
                    {
                        var current = change.Item.Current;
                        Remove(current);
                        break;
                    }

                case ListChangeReason.RemoveRange:
                    {
                        _innerList.RemoveMany(change.Range);
                        break;
                    }

                case ListChangeReason.Clear:
                    {
                        _innerList.Clear();
                        break;
                    }
                }
            });

            return(_innerList.CaptureChanges());
        }
Beispiel #2
0
        private void RegisterForRemoval(IChangeSet <T> changes)
        {
            changes.ForEach(change =>
            {
                switch (change.Reason)
                {
                case ListChangeReason.Replace:
                    change.Item.Previous.IfHasValue(t => _callback(t));
                    break;

                case ListChangeReason.Remove:
                    _callback(change.Item.Current);
                    break;

                case ListChangeReason.RemoveRange:
                    change.Range.ForEach(_callback);
                    break;

                case ListChangeReason.Clear:
                    _items.ForEach(_callback);
                    break;
                }
            });
            _items.Clone(changes);
        }
Beispiel #3
0
        public void RegisterForRemoval(IChangeSet <TObject, TKey> changes, Cache <TObject, TKey> cache)
        {
            changes.ForEach(change =>
            {
                switch (change.Reason)
                {
                case ChangeReason.Update:
                    change.Previous.IfHasValue(t => _removeAction(t));
                    break;

                case ChangeReason.Remove:
                    _removeAction(change.Current);
                    break;
                }
            });
            cache.Clone(changes);
        }
Beispiel #4
0
        private void RegisterForRemoval(IChangeSet <TObject, TKey> changes, InternalCache <TObject, TKey> cache)
        {
            changes.ForEach(change =>
            {
                switch (change.Reason)
                {
                case ChangeReason.Update:
                    // ReSharper disable once InconsistentlySynchronizedField
                    change.Previous.IfHasValue(t => _removeAction(t));
                    break;

                case ChangeReason.Remove:
                    // ReSharper disable once InconsistentlySynchronizedField
                    _removeAction(change.Current);
                    break;
                }
            });
            cache.Clone(changes);
        }
Beispiel #5
0
        private void CloneSourceList(ReferenceCountTracker <T> tracker, IChangeSet <T> changes)
        {
            changes.ForEach(change =>
            {
                switch (change.Reason)
                {
                case ListChangeReason.Add:
                    tracker.Add(change.Item.Current);
                    break;

                case ListChangeReason.AddRange:
                    foreach (var t in change.Range)
                    {
                        tracker.Add(t);
                    }
                    break;

                case ListChangeReason.Replace:
                    tracker.Remove(change.Item.Previous.Value);
                    tracker.Add(change.Item.Current);
                    break;

                case ListChangeReason.Remove:
                    tracker.Remove(change.Item.Current);
                    break;

                case ListChangeReason.RemoveRange:
                case ListChangeReason.Clear:
                    foreach (var t in change.Range)
                    {
                        tracker.Remove(t);
                    }
                    break;
                    //case ListChangeReason.Clear:
                    //    tracker.Clear();
                    //    break;
                }
            });
        }
Beispiel #6
0
        private void DoUpdate(IChangeSet <TObject, TKey> updates, IObservableCollection <TObject> list)
        {
            updates.ForEach(update =>
            {
                switch (update.Reason)
                {
                case ChangeReason.Add:
                    list.Add(update.Current);
                    break;

                case ChangeReason.Remove:
                    list.Remove(update.Current);
                    break;

                case ChangeReason.Update:
                    {
                        list.Remove(update.Previous.Value);
                        list.Add(update.Current);
                    }
                    break;
                }
            });
        }
Beispiel #7
0
        public IDictionary <object, IChange> Visit(IChangeSet changeSet)
        {
            var distinct = new Dictionary <object, IChange>();

            changeSet.ForEach(change =>
            {
                /*
                 * recuperiamo un riferimento alle entities
                 * che sono oggetto della modifica
                 */
                change.GetChangedEntities().ForEach(entity =>
                {
                    if (!distinct.ContainsKey(entity))
                    {
                        /*
                         * se l'entity non è tra quelle che abbiamo
                         * già incontrato la aggiungiamo.
                         */
                        distinct.Add(entity, change);
                    }
                    else
                    {
                        /*
                         * Se l'entity è già tra quelle visitate
                         * sostituiamo la IChange associata perchè
                         * la IChange più importante è l'ultima, che è
                         * quella che determina la ProposedActions che
                         * verrà proposta.
                         */
                        distinct[entity] = change;
                    }
                });
            });

            return(distinct);
        }
		public IDictionary<object, IChange> Visit( IChangeSet changeSet )
		{
			var distinct = new Dictionary<object, IChange>();

			changeSet.ForEach( change =>
			{
				/*
				 * recuperiamo un riferimento alle entities 
				 * che sono oggetto della modifica
				 */
				change.GetChangedEntities().ForEach( entity =>
				{
					if( !distinct.ContainsKey( entity ) )
					{
						/*
						 * se l'entity non è tra quelle che abbiamo
						 * già incontrato la aggiungiamo.
						 */
						distinct.Add( entity, change );
					}
					else
					{
						/*
						 * Se l'entity è già tra quelle visitate
						 * sostituiamo la IChange associata perchè
						 * la IChange più importante è l'ultima, che è
						 * quella che determina la ProposedActions che
						 * verrà proposta.
						 */
						distinct[ entity ] = change;
					}
				} );
			} );

			return distinct;
		}
Beispiel #9
0
        private IChangeSet <TValue> Process(IChangeSet <ItemWithValue <T, TValue> > updates)
        {
            Action <TValue> addAction = value => _valueCounters.Lookup(value)
                                        .IfHasValue(count => _valueCounters[value] = count + 1)
                                        .Else(() =>
            {
                _valueCounters[value] = 1;
                _result.Add(value);
            });

            Action <TValue> removeAction = value =>
            {
                var counter = _valueCounters.Lookup(value);
                if (!counter.HasValue)
                {
                    return;
                }

                //decrement counter
                var newCount = counter.Value - 1;
                _valueCounters[value] = newCount;
                if (newCount != 0)
                {
                    return;
                }

                //if there are none, then remove and notify
                _result.Remove(value);
            };

            updates.ForEach(change =>
            {
                switch (change.Reason)
                {
                case ListChangeReason.Add:
                    {
                        var value = change.Item.Current.Value;
                        addAction(value);
                        break;
                    }

                case ListChangeReason.AddRange:
                    {
                        change.Range.Select(item => item.Value).ForEach(addAction);
                        break;
                    }

                //	case ListChangeReason.Evaluate:
                case ListChangeReason.Replace:
                    {
                        var value    = change.Item.Current.Value;
                        var previous = change.Item.Previous.Value.Value;
                        if (value.Equals(previous))
                        {
                            return;
                        }

                        removeAction(previous);
                        addAction(value);
                        break;
                    }

                case ListChangeReason.Remove:
                    {
                        var previous = change.Item.Current.Value;
                        removeAction(previous);
                        break;
                    }

                case ListChangeReason.RemoveRange:
                    {
                        change.Range.Select(item => item.Value).ForEach(removeAction);
                        break;
                    }

                case ListChangeReason.Clear:
                    {
                        _result.Clear();
                        _valueCounters.Clear();
                        break;
                    }
                }
            });
            return(_result.CaptureChanges());
        }
Beispiel #10
0
        private void Transform(IChangeSet <TSource> changes)
        {
            if (changes == null)
            {
                throw new ArgumentNullException(nameof(changes));
            }

            _transformed.EnsureCapacityFor(changes);

            changes.ForEach(item =>
            {
                switch (item.Reason)
                {
                case ListChangeReason.Add:
                    {
                        var change = item.Item;
                        if (change.CurrentIndex < 0 | change.CurrentIndex >= _transformed.Count)
                        {
                            _transformed.Add(_containerFactory(change.Current));
                        }
                        else
                        {
                            _transformed.Insert(change.CurrentIndex, _containerFactory(change.Current));
                        }
                        break;
                    }

                case ListChangeReason.AddRange:
                    {
                        _transformed.AddOrInsertRange(item.Range.Select(_containerFactory), item.Range.Index);
                        break;
                    }

                case ListChangeReason.Replace:
                    {
                        var change = item.Item;
                        if (change.CurrentIndex == change.PreviousIndex)
                        {
                            _transformed[change.CurrentIndex] = _containerFactory(change.Current);
                        }
                        else
                        {
                            _transformed.RemoveAt(change.PreviousIndex);
                            _transformed.Insert(change.CurrentIndex, _containerFactory(change.Current));
                        }
                    }
                    break;

                case ListChangeReason.Remove:
                    {
                        var change    = item.Item;
                        bool hasIndex = change.CurrentIndex >= 0;

                        if (hasIndex)
                        {
                            _transformed.RemoveAt(item.Item.CurrentIndex);
                        }
                        else
                        {
                            var toremove = _transformed.FirstOrDefault(t => ReferenceEquals(t.Source, t));

                            if (toremove != null)
                            {
                                _transformed.Remove(toremove);
                            }
                        }
                    }
                    break;

                case ListChangeReason.RemoveRange:
                    {
                        if (item.Range.Index >= 0)
                        {
                            _transformed.RemoveRange(item.Range.Index, item.Range.Count);
                        }
                        else
                        {
                            var toremove = _transformed.Where(t => ReferenceEquals(t.Source, t)).ToArray();
                            _transformed.RemoveMany(toremove);
                        }
                    }
                    break;

                case ListChangeReason.Clear:
                    {
                        //i.e. need to store transformed reference so we can correctly clear
                        var toClear = new Change <TransformedItemContainer>(ListChangeReason.Clear, _transformed);
                        _transformed.ClearOrRemoveMany(toClear);
                    }
                    break;

                case ListChangeReason.Moved:
                    {
                        var change    = item.Item;
                        bool hasIndex = change.CurrentIndex >= 0;
                        if (!hasIndex)
                        {
                            throw new UnspecifiedIndexException("Cannot move as an index was not specified");
                        }

                        var collection = _transformed as IExtendedList <TransformedItemContainer>;
                        if (collection != null)
                        {
                            collection.Move(change.PreviousIndex, change.CurrentIndex);
                        }
                        else
                        {
                            var current = _transformed[change.PreviousIndex];
                            _transformed.RemoveAt(change.PreviousIndex);
                            _transformed.Insert(change.CurrentIndex, current);
                        }
                        break;
                    }
                }
            });
        }
Beispiel #11
0
        /// <summary>
        /// Clones the source list with the specified change set, transforming the items using the specified factory
        /// </summary>
        /// <typeparam name="TSource">The type of the source.</typeparam>
        /// <typeparam name="TDestination">The type of the destination.</typeparam>
        /// <param name="source">The source.</param>
        /// <param name="changes">The changes.</param>
        /// <param name="transformFactory">The transform factory.</param>
        /// <exception cref="System.ArgumentNullException">
        /// source
        /// or
        /// changes
        /// or
        /// transformFactory
        /// </exception>
        public static void Transform <TSource, TDestination>(this IList <TDestination> source, IChangeSet <TSource> changes, Func <TSource, TDestination> transformFactory)
        {
            if (source == null)
            {
                throw new ArgumentNullException(nameof(source));
            }
            if (changes == null)
            {
                throw new ArgumentNullException(nameof(changes));
            }
            if (transformFactory == null)
            {
                throw new ArgumentNullException(nameof(transformFactory));
            }

            source.EnsureCapacityFor(changes);
            changes.ForEach(item =>
            {
                switch (item.Reason)
                {
                case ListChangeReason.Add:
                    {
                        var change = item.Item;
                        source.Insert(change.CurrentIndex, transformFactory(change.Current));
                        break;
                    }

                case ListChangeReason.AddRange:
                    {
                        source.AddOrInsertRange(item.Range.Select(transformFactory), item.Range.Index);
                        break;
                    }

                case ListChangeReason.Replace:
                    {
                        var change = item.Item;
                        if (change.CurrentIndex == change.PreviousIndex)
                        {
                            source[change.CurrentIndex] = transformFactory(change.Current);
                        }
                        else
                        {
                            source.RemoveAt(change.PreviousIndex);
                            source.Insert(change.CurrentIndex, transformFactory(change.Current));
                        }
                    }
                    break;

                case ListChangeReason.Remove:
                    {
                        source.RemoveAt(item.Item.CurrentIndex);
                    }
                    break;

                case ListChangeReason.RemoveRange:
                    {
                        source.RemoveRange(item.Range.Index, item.Range.Count);
                    }
                    break;

                case ListChangeReason.Clear:
                    {
                        source.Clear();
                    }
                    break;
                }
            });
        }
Beispiel #12
0
        internal static void CloneReactiveList <T>(this ReactiveList <T> source, IChangeSet <T> changes)
        {
            if (source == null)
            {
                throw new ArgumentNullException(nameof(source));
            }
            if (changes == null)
            {
                throw new ArgumentNullException(nameof(changes));
            }

            changes.ForEach(item =>
            {
                switch (item.Reason)
                {
                case ListChangeReason.Add:
                    {
                        var change   = item.Item;
                        var hasIndex = change.CurrentIndex >= 0;
                        if (hasIndex)
                        {
                            source.Insert(change.CurrentIndex, change.Current);
                        }
                        else
                        {
                            source.Add(change.Current);
                        }
                        break;
                    }

                case ListChangeReason.AddRange:
                    {
                        var startingIndex = item.Range.Index;

                        if (RxApp.SupportsRangeNotifications)
                        {
                            if (startingIndex >= 0)
                            {
                                source.InsertRange(startingIndex, item.Range);
                            }
                            else
                            {
                                source.AddRange(item.Range);
                            }
                        }
                        else
                        {
                            if (startingIndex >= 0)
                            {
                                item.Range.Reverse().ForEach(t => source.Insert(startingIndex, t));
                            }
                            else
                            {
                                item.Range.ForEach(source.Add);
                            }
                        }

                        break;
                    }

                case ListChangeReason.Clear:
                    {
                        source.Clear();
                        break;
                    }

                case ListChangeReason.Replace:
                    {
                        var change    = item.Item;
                        bool hasIndex = change.CurrentIndex >= 0;
                        if (hasIndex && change.CurrentIndex == change.PreviousIndex)
                        {
                            source[change.CurrentIndex] = change.Current;
                        }
                        else
                        {
                            source.RemoveAt(change.PreviousIndex);
                            source.Insert(change.CurrentIndex, change.Current);
                        }
                    }
                    break;

                case ListChangeReason.Remove:
                    {
                        var change    = item.Item;
                        bool hasIndex = change.CurrentIndex >= 0;
                        if (hasIndex)
                        {
                            source.RemoveAt(change.CurrentIndex);
                        }
                        else
                        {
                            source.Remove(change.Current);
                        }
                        break;
                    }

                case ListChangeReason.RemoveRange:
                    {
                        if (RxApp.SupportsRangeNotifications && item.Range.Index >= 0)
                        {
                            source.RemoveRange(item.Range.Index, item.Range.Count);
                        }
                        else
                        {
                            source.RemoveMany(item.Range);
                        }
                    }
                    break;

                case ListChangeReason.Moved:
                    {
                        var change    = item.Item;
                        bool hasIndex = change.CurrentIndex >= 0;
                        if (!hasIndex)
                        {
                            throw new UnspecifiedIndexException("Cannot move as an index was not specified");
                        }

                        source.Move(change.PreviousIndex, change.CurrentIndex);
                        break;
                    }
                }
            });
        }
Beispiel #13
0
 private void UpdateResultList(MergeContainer[] sourceLists, IChangeSet <TObject, TKey> changes)
 {
     changes.ForEach(change => { ProcessItem(sourceLists, change.Current, change.Key); });
 }
Beispiel #14
0
        /// <summary>
        /// Clones the list from the specified change set
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source">The source.</param>
        /// <param name="changes">The changes.</param>
        /// <exception cref="System.ArgumentNullException">
        /// source
        /// or
        /// changes
        /// </exception>
        public static void Clone <T>(this IList <T> source, IChangeSet <T> changes)
        {
            if (source == null)
            {
                throw new ArgumentNullException(nameof(source));
            }
            if (changes == null)
            {
                throw new ArgumentNullException(nameof(changes));
            }

            changes.ForEach(item =>
            {
                switch (item.Reason)
                {
                case ListChangeReason.Add:
                    {
                        var change    = item.Item;
                        bool hasIndex = change.CurrentIndex >= 0;
                        if (hasIndex)
                        {
                            source.Insert(change.CurrentIndex, change.Current);
                        }
                        else
                        {
                            source.Add(change.Current);
                        }
                        break;
                    }

                case ListChangeReason.AddRange:
                    {
                        source.AddOrInsertRange(item.Range, item.Range.Index);
                        break;
                    }

                case ListChangeReason.Clear:
                    {
                        source.Clear();
                        break;
                    }

                case ListChangeReason.Replace:
                    {
                        var change    = item.Item;
                        bool hasIndex = change.CurrentIndex >= 0;
                        if (hasIndex && change.CurrentIndex == change.PreviousIndex)
                        {
                            source[change.CurrentIndex] = change.Current;
                        }
                        else
                        {
                            //is this best? or replace + move?
                            source.RemoveAt(change.PreviousIndex);
                            source.Insert(change.CurrentIndex, change.Current);
                        }
                    }
                    break;

                case ListChangeReason.Remove:
                    {
                        var change    = item.Item;
                        bool hasIndex = change.CurrentIndex >= 0;
                        if (hasIndex)
                        {
                            source.RemoveAt(change.CurrentIndex);
                        }
                        else
                        {
                            source.Remove(change.Current);
                        }

                        break;
                    }

                case ListChangeReason.RemoveRange:
                    {
                        //ignore this case because WhereReasonsAre removes the index [in which case call RemoveMany]
                        //if (item.Range.Index < 0)
                        //    throw new UnspecifiedIndexException("ListChangeReason.RemoveRange should not have an index specified index");

                        if (item.Range.Index >= 0 && (source is IExtendedList <T> || source is List <T>))
                        {
                            source.RemoveRange(item.Range.Index, item.Range.Count);
                        }
                        else
                        {
                            source.RemoveMany(item.Range);
                        }
                    }
                    break;

                case ListChangeReason.Moved:
                    {
                        var change    = item.Item;
                        bool hasIndex = change.CurrentIndex >= 0;
                        if (!hasIndex)
                        {
                            throw new UnspecifiedIndexException("Cannot move as an index was not specified");
                        }

                        var collection = source as IExtendedList <T>;
                        if (collection != null)
                        {
                            collection.Move(change.PreviousIndex, change.CurrentIndex);
                        }
                        else
                        {
                            //check this works whatever the index is
                            source.RemoveAt(change.PreviousIndex);
                            source.Insert(change.CurrentIndex, change.Current);
                        }
                        break;
                    }
                }
            });
        }
Beispiel #15
0
        public IDistinctChangeSet <TValue> Calculate(IChangeSet <TObject, TKey> updates)
        {
            var result = new List <Change <TValue, TValue> >();

            Action <TValue> addAction = value => _valueCounters.Lookup(value)
                                        .IfHasValue(count => _valueCounters[value] = count + 1)
                                        .Else(() =>
            {
                _valueCounters[value] = 1;
                result.Add(new Change <TValue, TValue>(ChangeReason.Add, value, value));
            });

            Action <TValue> removeAction = value =>
            {
                var counter = _valueCounters.Lookup(value);
                if (!counter.HasValue)
                {
                    return;
                }

                //decrement counter
                var newCount = counter.Value - 1;
                _valueCounters[value] = newCount;
                if (newCount != 0)
                {
                    return;
                }

                //if there are none, then remove and notify
                _valueCounters.Remove(value);
                result.Add(new Change <TValue, TValue>(ChangeReason.Remove, value, value));
            };

            updates.ForEach(change =>
            {
                var key = change.Key;
                switch (change.Reason)
                {
                case ChangeReason.Add:
                    {
                        var value = _valueSelector(change.Current);
                        addAction(value);
                        _itemCache[key] = value;
                        break;
                    }

                case ChangeReason.Evaluate:
                case ChangeReason.Update:
                    {
                        var value    = _valueSelector(change.Current);
                        var previous = _itemCache[key];
                        if (value.Equals(previous))
                        {
                            return;
                        }

                        removeAction(previous);
                        addAction(value);
                        _itemCache[key] = value;
                        break;
                    }

                case ChangeReason.Remove:
                    {
                        var previous = _itemCache[key];
                        removeAction(previous);
                        _itemCache.Remove(key);
                        break;
                    }
                }
            });
            return(new DistinctChangeSet <TValue>(result));
        }
Beispiel #16
0
        /// <summary>
        /// Filters the source from the changes, using the specified predicate
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source">The source.</param>
        /// <param name="changes">The changes.</param>
        /// <param name="predicate">The predicate.</param>
        public static void Filter <T>(this IList <T> source, IChangeSet <T> changes, Func <T, bool> predicate)
        {
            if (source == null)
            {
                throw new ArgumentNullException(nameof(source));
            }
            if (changes == null)
            {
                throw new ArgumentNullException(nameof(changes));
            }
            if (predicate == null)
            {
                throw new ArgumentNullException(nameof(predicate));
            }

            //TODO: Check for missing index

            changes.ForEach(item =>
            {
                switch (item.Reason)
                {
                case ListChangeReason.Add:
                    {
                        var change = item.Item;
                        var match  = predicate(change.Current);
                        if (match)
                        {
                            source.Add(change.Current);
                        }
                    }
                    break;

                case ListChangeReason.AddRange:
                    {
                        var matches = item.Range.Where(predicate).ToList();
                        source.AddRange(matches);
                    }
                    break;


                case ListChangeReason.Replace:
                    {
                        var change   = item.Item;
                        var match    = predicate(change.Current);
                        var wasMatch = predicate(change.Previous.Value);

                        if (match)
                        {
                            if (wasMatch)
                            {
                                //an update, so get the latest index
                                var previous = source.FindItemAndIndex(change.Previous.Value, ReferenceEqualityComparer <T> .Instance)
                                               .ValueOrThrow(() => new InvalidOperationException("Cannot find item. Expected to be in the list"));

                                //replace inline
                                source[previous.Index] = change.Current;
                            }
                            else
                            {
                                source.Add(change.Current);
                            }
                        }
                        else
                        {
                            if (wasMatch)
                            {
                                source.Remove(change.Previous.Value);
                            }
                        }
                    }

                    break;

                case ListChangeReason.Remove:
                    {
                        var change   = item.Item;
                        var wasMatch = predicate(change.Current);
                        if (wasMatch)
                        {
                            source.Remove(change.Current);
                        }
                    }
                    break;

                case ListChangeReason.RemoveRange:
                    {
                        source.RemoveMany(item.Range.Where(predicate));
                    }
                    break;

                case ListChangeReason.Clear:
                    {
                        source.Clear();
                    }
                    break;
                }
            });
        }
Beispiel #17
0
        /// <summary>
        /// Clones the source list with the specified change set, transforming the items using the specified factory
        /// </summary>
        /// <typeparam name="TSource">The type of the source.</typeparam>
        /// <typeparam name="TDestination">The type of the destination.</typeparam>
        /// <param name="source">The source.</param>
        /// <param name="changes">The changes.</param>
        /// <param name="transformFactory">The transform factory.</param>
        /// <exception cref="System.ArgumentNullException">
        /// source
        /// or
        /// changes
        /// or
        /// transformFactory
        /// </exception>
        public static void Transform <TSource, TDestination>(this IList <TDestination> source, IChangeSet <TSource> changes, Func <TSource, TDestination> transformFactory)
        {
            if (source == null)
            {
                throw new ArgumentNullException(nameof(source));
            }
            if (changes == null)
            {
                throw new ArgumentNullException(nameof(changes));
            }
            if (transformFactory == null)
            {
                throw new ArgumentNullException(nameof(transformFactory));
            }

            source.EnsureCapacityFor(changes);
            changes.ForEach(item =>
            {
                switch (item.Reason)
                {
                case ListChangeReason.Add:
                    {
                        var change = item.Item;
                        source.Insert(change.CurrentIndex, transformFactory(change.Current));
                        break;
                    }

                case ListChangeReason.AddRange:
                    {
                        source.AddOrInsertRange(item.Range.Select(transformFactory), item.Range.Index);
                        break;
                    }

                case ListChangeReason.Replace:
                    {
                        var change = item.Item;
                        if (change.CurrentIndex == change.PreviousIndex)
                        {
                            source[change.CurrentIndex] = transformFactory(change.Current);
                        }
                        else
                        {
                            source.RemoveAt(change.PreviousIndex);
                            source.Insert(change.CurrentIndex, transformFactory(change.Current));
                        }
                    }
                    break;

                case ListChangeReason.Remove:
                    {
                        source.RemoveAt(item.Item.CurrentIndex);
                    }
                    break;

                case ListChangeReason.RemoveRange:
                    {
                        source.RemoveRange(item.Range.Index, item.Range.Count);
                    }
                    break;

                case ListChangeReason.Clear:
                    {
                        //TODO: Need to resolve the issue of not being able to use ClearOrRemoveMany()!!!
                        //i.e. need to store transformed reference so we can correctly clear
                        source.Clear();
                    }
                    break;
                }
            });
        }