Skip to content

Commit

Permalink
fix: Improve efficiency of AddKeyEnumerator (#568)
Browse files Browse the repository at this point in the history
* A replace in an observable changeset with a key (i.e. cache style collection) should only produce an Add/Remove when the keys do not match. Otherwise it should produce an Update.

* simplify explanation
  • Loading branch information
pdegenhardt authored Mar 10, 2022
1 parent b38c0d0 commit 64d3df4
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 3 deletions.
49 changes: 49 additions & 0 deletions src/DynamicData.Tests/ObservableCollectionExFixture.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@

using System.Collections.ObjectModel;
using DynamicData.Binding;
using DynamicData.Tests.Domain;

using FluentAssertions;

using Xunit;

namespace DynamicData.Tests;

public class ObservableCollectionExFixture
{
private readonly Person _person1 = new("One", 1);

private readonly Person _person2 = new("Two", 2);

private readonly Person _person3 = new("Three", 3);

[Fact]
public void CanConvertToObservableChangeSetList()
{
var source = new ObservableCollection<Person> { _person1, _person2, _person3 };
var changeSet = source.ToObservableChangeSet().AsObservableList();
changeSet.Items.Should().BeEquivalentTo(source);
}

[Fact]
public void CanConvertToObservableChangeSetCache()
{
var source = new ObservableCollection<Person> { _person1, _person2, _person3 };
var changeSet = source.ToObservableChangeSet(x => x.Name).AsObservableCache();
changeSet.Items.Should().BeEquivalentTo(source);
var one = changeSet.Lookup("One").Value;
one.Should().BeEquivalentTo(_person1);
}


[Fact]
public void ReplacingAnItemWithSameProducesUpdate()
{
var source = new ObservableCollection<Person> { _person1, _person2, _person3 };
var aggregator = source.ToObservableChangeSet(x => x.Name).AsAggregator();
source[0] = new Person("One", 100);
aggregator.Summary.Latest.Updates.Should().Be(1);
aggregator.Summary.Latest.Adds.Should().Be(0);
aggregator.Summary.Latest.Removes.Should().Be(0);
}
}
15 changes: 12 additions & 3 deletions src/DynamicData/List/Linq/AddKeyEnumerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,14 +55,23 @@ public IEnumerator<Change<TObject, TKey>> GetEnumerator()

case ListChangeReason.Replace:
{
// replace is a remove and add
// replace is a remove and add, if and only if, the keys do not match
var previous = change.Item.Previous.Value;
var previousKey = _keySelector(previous);
yield return new Change<TObject, TKey>(ChangeReason.Remove, previousKey, previous);

var current = change.Item.Current;
var currentKey = _keySelector(current);
yield return new Change<TObject, TKey>(ChangeReason.Add, currentKey, current);

if (Equals(currentKey, previousKey))
{
yield return new Change<TObject, TKey>(ChangeReason.Update, currentKey, current, previous);
}
else
{
yield return new Change<TObject, TKey>(ChangeReason.Remove, previousKey, previous);

yield return new Change<TObject, TKey>(ChangeReason.Add, currentKey, current);
}

break;
}
Expand Down

0 comments on commit 64d3df4

Please sign in to comment.