66using System . Collections . Specialized ;
77using System . ComponentModel ;
88using System . Diagnostics ;
9+ using System . Runtime . Serialization ;
910
1011namespace System . Collections . ObjectModel
1112{
@@ -17,6 +18,7 @@ namespace System.Collections.ObjectModel
1718 [ Serializable ]
1819 [ DebuggerTypeProxy ( typeof ( CollectionDebugView < > ) ) ]
1920 [ DebuggerDisplay ( "Count = {Count}" ) ]
21+ [ System . Runtime . CompilerServices . TypeForwardedFrom ( "WindowsBase, Version=3.0.0.0, Culture=Neutral, PublicKeyToken=31bf3856ad364e35" ) ]
2022 public class ObservableCollection < T > : Collection < T > , INotifyCollectionChanged , INotifyPropertyChanged
2123 {
2224 //------------------------------------------------------
@@ -238,10 +240,16 @@ protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
238240 NotifyCollectionChangedEventHandler handler = CollectionChanged ;
239241 if ( handler != null )
240242 {
241- using ( BlockReentrancy ( ) )
243+ // Not calling BlockReentrancy() here to avoid the SimpleMonitor allocation.
244+ _blockReentrancyCount ++ ;
245+ try
242246 {
243247 handler ( this , e ) ;
244248 }
249+ finally
250+ {
251+ _blockReentrancyCount -- ;
252+ }
245253 }
246254 }
247255
@@ -260,16 +268,16 @@ protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
260268 /// </remarks>
261269 protected IDisposable BlockReentrancy ( )
262270 {
263- _monitor . Enter ( ) ;
264- return _monitor ;
271+ _blockReentrancyCount ++ ;
272+ return EnsureMonitorInitialized ( ) ;
265273 }
266274
267275 /// <summary> Check and assert for reentrant attempts to change this collection. </summary>
268276 /// <exception cref="InvalidOperationException"> raised when changing the collection
269277 /// while another collection change is still being notified to other listeners </exception>
270278 protected void CheckReentrancy ( )
271279 {
272- if ( _monitor . Busy )
280+ if ( _blockReentrancyCount > 0 )
273281 {
274282 // we can allow changes if there's only one listener - the problem
275283 // only arises if reentrant changes make the original event args
@@ -337,6 +345,25 @@ private void OnCollectionReset()
337345 {
338346 OnCollectionChanged ( EventArgsCache . ResetCollectionChanged ) ;
339347 }
348+
349+ private SimpleMonitor EnsureMonitorInitialized ( )
350+ {
351+ return _monitor ?? ( _monitor = new SimpleMonitor ( this ) ) ;
352+ }
353+
354+ [ OnSerializing ]
355+ private void OnSerializing ( StreamingContext context )
356+ {
357+ EnsureMonitorInitialized ( ) ;
358+ _monitor . _busyCount = _blockReentrancyCount ;
359+ }
360+
361+ [ OnDeserialized ]
362+ private void OnDeserialized ( StreamingContext context )
363+ {
364+ _blockReentrancyCount = _monitor . _busyCount ;
365+ _monitor . _collection = this ;
366+ }
340367 #endregion Private Methods
341368
342369 //------------------------------------------------------
@@ -349,21 +376,24 @@ private void OnCollectionReset()
349376
350377 // this class helps prevent reentrant calls
351378 [ Serializable ]
352- private class SimpleMonitor : IDisposable
379+ [ System . Runtime . CompilerServices . TypeForwardedFrom ( "WindowsBase, Version=3.0.0.0, Culture=Neutral, PublicKeyToken=31bf3856ad364e35" ) ]
380+ private sealed class SimpleMonitor : IDisposable
353381 {
354- public void Enter ( )
382+ internal int _busyCount ; // Only used during (de)serialization to maintain compatibility with desktop.
383+
384+ [ NonSerialized ]
385+ internal ObservableCollection < T > _collection ;
386+
387+ public SimpleMonitor ( ObservableCollection < T > collection )
355388 {
356- ++ _busyCount ;
389+ Debug . Assert ( collection != null ) ;
390+ _collection = collection ;
357391 }
358392
359393 public void Dispose ( )
360394 {
361- -- _busyCount ;
395+ _collection . _blockReentrancyCount -- ;
362396 }
363-
364- public bool Busy { get { return _busyCount > 0 ; } }
365-
366- int _busyCount ;
367397 }
368398
369399 #endregion Private Types
@@ -376,7 +406,10 @@ public void Dispose()
376406
377407 #region Private Fields
378408
379- private readonly SimpleMonitor _monitor = new SimpleMonitor ( ) ;
409+ private SimpleMonitor _monitor ; // Lazily allocated only when a subclass calls BlockReentrancy() or during serialization.
410+
411+ [ NonSerialized ]
412+ private int _blockReentrancyCount ;
380413 #endregion Private Fields
381414 }
382415
0 commit comments