From 0544fb5efdccbaa1a8973fedcc4d9ed5972d2713 Mon Sep 17 00:00:00 2001 From: Jerome Laban Date: Sun, 24 Nov 2024 22:25:07 -0500 Subject: [PATCH] perf: Don't use multicast delegates for DependencyObjectCollection.VectorChanged This change avoids the high cost of multicast delegates, particularly on mono-AOT environments. We also do not need the thread safety guarantees. --- .../UI/Xaml/DependencyObjectCollection.cs | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/Uno.UI/UI/Xaml/DependencyObjectCollection.cs b/src/Uno.UI/UI/Xaml/DependencyObjectCollection.cs index 70003d443970..c7243f7dcba0 100644 --- a/src/Uno.UI/UI/Xaml/DependencyObjectCollection.cs +++ b/src/Uno.UI/UI/Xaml/DependencyObjectCollection.cs @@ -25,7 +25,14 @@ public partial class DependencyObjectCollectionBase : DependencyObject public partial class DependencyObjectCollection : DependencyObjectCollectionBase, IList, IEnumerable, IEnumerable, IObservableVector where T : DependencyObject { - public event VectorChangedEventHandler VectorChanged; + // Explicit handlers list to avoid the cost of multicast delegates handling + private List> _vectorChangedHandlers; + + public event VectorChangedEventHandler VectorChanged + { + add => (_vectorChangedHandlers ??= new()).Add(value); + remove => (_vectorChangedHandlers ??= new()).Remove(value); + } private readonly List _list = new List(); @@ -205,7 +212,17 @@ internal List.Enumerator GetEnumeratorFast() => _list.GetEnumerator(); private void RaiseVectorChanged(CollectionChange change, int index) - => VectorChanged?.Invoke(this, new VectorChangedEventArgs(change, (uint)index)); + { + if (_vectorChangedHandlers is not null) + { + var args = new VectorChangedEventArgs(change, (uint)index); + + foreach (var handler in _vectorChangedHandlers) + { + handler.Invoke(this, args); + } + } + } private protected virtual void OnAdded(T d) {