Skip to content

Thread-Safe Observed Collection

The TSObservedCollection class in the ByteCobra.Observables.ThreadSafe namespace extends the ObservableCollection to provide a thread-safe, observable collection of items of type T. It implements the IObservedCollection and IThreadSafe interfaces, and leverages the Monitor class to synchronize access to the collection and its subscribers.

The TSObservedCollection class synchronizes access to the collection and its list of subscribers using a lockObject and the Monitor class from the System.Threading namespace. Methods that modify the collection or its subscribers first attempt to acquire a lock using Monitor.TryEnter, and release the lock using Monitor.Exit. This ensures that only one thread can access these critical sections at a time, preventing race conditions.

The NotifyChanged and NotifySubscribers methods are used to inform registered callbacks of changes to the collection. When a change occurs, NotifyChanged creates a copy of the subscribers list, iterates through the copy, and invokes each callback with the item and change type. This design prevents issues that could arise from modifying the subscribers list while iterating through it, which might occur if a callback modifies the subscribers list.

The HandleExceptions property and exception handling within the NotifySubscribers method provide a mechanism to catch and optionally rethrow exceptions that occur during the invocation of callbacks. This is useful in scenarios where an exception in one callback should not prevent other callbacks from being invoked.


  • bool HandleExceptions: Determines if exceptions during change notifications are handled internally.
  • TimeSpan LockTimeout: Specifies the timeout period for acquiring a lock on the collection.
  • IEnumerable<T> Values: Gets or sets the items in the collection.


  • void SetSilently(IEnumerable<T> items): Sets the items in the collection without notifying subscribers.
  • void Subscribe(Action<T, NotifyCollectionChangedAction> callback): Registers a callback to be invoked on collection changes.
  • void Unsubscribe(Action<T, NotifyCollectionChangedAction> callback): Unregisters a previously registered callback.
  • void ClearAll(): Clears all items from the collection.
  • void ClearSubscriptions(): Clears all registered callbacks.
  • void NotifyChanged(NotifyCollectionChangedEventArgs e): Notifies subscribers based on the provided NotifyCollectionChangedEventArgs.
  • void NotifyChanged(T item, NotifyCollectionChangedAction changeType): Notifies subscribers of a specified change.
  • protected virtual void NotifySubscribers(T item, NotifyCollectionChangedAction changeType): Invokes all registered callbacks with the specified item and change type.


var tsObservedCollection = new TSObservedCollection<int>();

tsObservedCollection.Subscribe((item, action) =>
    Debug.Log($"Item {item} was {action}");

tsObservedCollection.Add(1);  // Output: Item 1 was Added