From 43eb4e6b596f121aa0b001de0e40852232487cf7 Mon Sep 17 00:00:00 2001 From: h3xds1nz Date: Tue, 31 Dec 2024 08:17:19 +0100 Subject: [PATCH] Replace ArrayList/ICollection used for changelog in CollectionView with generic List (#9853) * Replace ArrayList/ICollection with List * Rename EmptyArrayList -> s_emptyList * Values inside changeLog can never be NULL and we no longer need to cast * _changeLog can never be NULL, re-init is under same lock --- .../System/Windows/Data/CollectionView.cs | 59 ++++++++----------- 1 file changed, 25 insertions(+), 34 deletions(-) diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Data/CollectionView.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Data/CollectionView.cs index 53a44c03321..5a8fc07ac59 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Data/CollectionView.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Data/CollectionView.cs @@ -1208,7 +1208,7 @@ protected virtual void OnAllowsCrossThreadChangesChanged() /// protected void ClearPendingChanges() { - lock(_changeLog.SyncRoot) + lock (_changeLogLock) { _changeLog.Clear(); _tempChangeLog.Clear(); @@ -1227,7 +1227,7 @@ protected void ClearPendingChanges() /// protected void ProcessPendingChanges() { - lock(_changeLog.SyncRoot) + lock (_changeLogLock) { ProcessChangeLog(_changeLog, true); _changeLog.Clear(); @@ -1815,24 +1815,17 @@ private void EndDefer() /// processed. /// /// - /// ArrayList of NotifyCollectionChangedEventArgs that could not be precessed. + /// List of NotifyCollectionChangedEventArgs that could not be precessed. /// - private void DeferProcessing(ICollection changeLog) + private void DeferProcessing(List changeLog) { Debug.Assert(changeLog != null && changeLog.Count > 0, "don't defer when there's no work"); - lock(SyncRoot) + lock (SyncRoot) { - lock(_changeLog.SyncRoot) + lock (_changeLogLock) { - if (_changeLog == null) - { - _changeLog = new ArrayList(changeLog); - } - else - { - _changeLog.InsertRange(0, changeLog); - } + _changeLog.InsertRange(0, changeLog); if (_databindOperation != null) { @@ -1854,21 +1847,15 @@ private void DeferProcessing(ICollection changeLog) /// /// List of NotifyCollectionChangedEventArgs that is to be processed. /// - private ICollection ProcessChangeLog(ArrayList changeLog, bool processAll=false) + private List ProcessChangeLog(List changeLog, bool processAll = false) { int currentIndex = 0; bool mustDeferProcessing = false; long beginTime = DateTime.Now.Ticks; - int startCount = changeLog.Count; - for ( ; currentIndex < changeLog.Count && !(mustDeferProcessing); currentIndex++) + for ( ; currentIndex < changeLog.Count && !mustDeferProcessing; currentIndex++) { - NotifyCollectionChangedEventArgs args = changeLog[currentIndex] as NotifyCollectionChangedEventArgs; - - if (args != null) - { - ProcessCollectionChanged(args); - } + ProcessCollectionChanged(changeLog[currentIndex]); if (!processAll) { @@ -1879,7 +1866,7 @@ private ICollection ProcessChangeLog(ArrayList changeLog, bool processAll=false) if (mustDeferProcessing && currentIndex < changeLog.Count) { // create an unprocessed subset of changeLog - changeLog.RemoveRange(0,currentIndex); + changeLog.RemoveRange(0, currentIndex); return changeLog; } @@ -1907,9 +1894,9 @@ private void SetFlag(CollectionViewFlags flags, bool value) // Post a change on the UI thread Dispatcher and updated the _changeLog. private void PostChange(NotifyCollectionChangedEventArgs args) { - lock(SyncRoot) + lock (SyncRoot) { - lock(_changeLog.SyncRoot) + lock (_changeLogLock) { // we can ignore everything before a Reset if (args.Action == NotifyCollectionChangedAction.Reset) @@ -1948,18 +1935,18 @@ private object ProcessInvoke(object arg) { // work on a private copy of the change log, so that other threads // can add to the main change log - lock(SyncRoot) + lock (SyncRoot) { - lock(_changeLog.SyncRoot) + lock (_changeLogLock) { _databindOperation = null; _tempChangeLog = _changeLog; - _changeLog = new ArrayList(); + _changeLog = new List(); } } // process the changes - ICollection unprocessedChanges = ProcessChangeLog(_tempChangeLog); + List unprocessedChanges = ProcessChangeLog(_tempChangeLog); // if changes remain (because we ran out of time), reschedule them if (unprocessedChanges != null && unprocessedChanges.Count > 0) @@ -1967,7 +1954,7 @@ private object ProcessInvoke(object arg) DeferProcessing(unprocessedChanges); } - _tempChangeLog = EmptyArrayList; + _tempChangeLog = s_emptyList; return null; } @@ -2154,8 +2141,11 @@ private enum CollectionViewFlags //------------------------------------------------------ #region Private Fields - ArrayList _changeLog = new ArrayList(); - ArrayList _tempChangeLog = EmptyArrayList; + private readonly Lock _changeLogLock = new(); + + private List _changeLog = new(); + private List _tempChangeLog = s_emptyList; + DataBindOperation _databindOperation; object _vmData; // view manager's private data IEnumerable _sourceCollection; // the underlying collection @@ -2173,7 +2163,8 @@ private enum CollectionViewFlags object _syncObject = new object(); DataBindEngine _engine; int _timestamp; - static readonly ArrayList EmptyArrayList = new ArrayList(); + + private static readonly List s_emptyList = new(); static readonly string IEnumerableT = typeof(IEnumerable<>).Name; internal static readonly object NoNewItem = new NamedObject("NoNewItem");