-
-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Implement copy-on-write collection for LogicalChildren/VisualChildren #20028
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Implement copy-on-write collection for LogicalChildren/VisualChildren #20028
Conversation
Changed Visual/Logical Children properties to use CopyOnWrite
|
|
||
| for (var i = 0; i < visualChildrenCount; i++) | ||
|
|
||
| foreach (var child in VisualChildren) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You haven't replaced VisualChildren with the new list type, is that an oversight?
| { | ||
| internal class SafeEnumerableList<T> : IAvaloniaList<T>, INotifyCollectionChanged | ||
| { | ||
| private AvaloniaList<T> _list = new(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm a bit worried about the allocations here. We have this inner list, plus the two event handlers in the constructor, or 3 extra allocations. I wouldn't worry about such a number in most other classes, but this is used in every visual, twice. That's 6 long-lived objects per visual.
|
|
||
| public void AddRange(IEnumerable<T> items) | ||
| { | ||
| ((IAvaloniaList<T>)GetList()).AddRange(items); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here and below: the cast seems unnecessary.
| return GetEnumerator(); | ||
| } | ||
|
|
||
| private AvaloniaList<T> GetList() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: rename to GetWriteableList (or something along those lines) to make the difference clearer.
| } | ||
| }; | ||
| }); | ||
| /*IDataTemplate windowTemplate = new FuncDataTemplate<object?>((i, ns) => |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove all the commented code in this file.
|
|
||
| namespace Avalonia.Base.UnitTests.Collections | ||
| { | ||
| public class SafeEnumerateCollectionTests |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While it's neat to have a test corresponding to real issue, a handful of tests for the SafeEnumerableList itself would be nice, i.e. checking that adding or removing an item doesn't affect enumerations that are already in progress.
| { | ||
| private readonly SafeEnumerableList<T> _owner; | ||
| private readonly int _generation; | ||
| private readonly IEnumerator<T> _enumerator; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be typed as AvaloniaList<T>.Enumerator to avoid boxing. (Make it non-readonly in that case.)
|
|
||
| object IEnumerator.Current => _enumerator.Current!; | ||
|
|
||
| public void Reset() => throw new InvalidOperationException(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's unlikely to be used, but why is Reset not implemented? The underlying list cannot change so it should be safe to call _enumerator.Reset().
What does the pull request do?
Fixes #14437 & #13497
What is the updated/expected behavior with this PR?
ControlCatalog doesn't fail anymore using scenario from #13497
How was the solution implemented (if it's not obvious)?
implemented new SafeEnumerableList class using "Copy-on-change" behavior and LogicalChildren/VisualChildren collections are changed to be instanced using class
Checklist
Fixed issues
Fixes #14437
Fixes #13497