Created
July 28, 2025 22:54
-
-
Save rquackenbush/796ccf839e58a0bb11c0ca4ea937a049 to your computer and use it in GitHub Desktop.
Simple notification framework to let interested parties know that something has happened in a decoupled way.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System.Collections.Concurrent; | |
| namespace TheNotifer; | |
| internal class NotificationSource : IDisposable | |
| { | |
| private bool _disposed; | |
| private readonly ConcurrentDictionary<IDisposable, Subscription> _notifications = new ConcurrentDictionary<IDisposable, Subscription>(); | |
| public void Notify() | |
| { | |
| foreach (var subscription in _notifications.Values.ToArray()) | |
| { | |
| try | |
| { | |
| subscription.Notify(); | |
| } | |
| catch (Exception) | |
| { | |
| } | |
| } | |
| } | |
| public IDisposable Subscribe(Action action) | |
| { | |
| if (action is null) | |
| throw new ArgumentNullException(nameof(action)); | |
| var subscription = new Subscription(this, action); | |
| if (!_notifications.TryAdd(subscription, subscription)) | |
| throw new InvalidOperationException("Unable to add subscription. Weird."); | |
| return subscription; | |
| } | |
| internal void Unsubscribe(IDisposable subscription) | |
| { | |
| _notifications.TryRemove(subscription, out _); | |
| } | |
| public void Dispose() | |
| { | |
| if (!_disposed) | |
| { | |
| _disposed = true; | |
| GC.SuppressFinalize(this); | |
| } | |
| } | |
| } | |
| internal class Subscription : IDisposable | |
| { | |
| private bool _disposed; | |
| private readonly NotificationSource _owner; | |
| private readonly Action _action; | |
| public Subscription(NotificationSource owner, Action action) | |
| { | |
| _owner = owner ?? throw new ArgumentNullException(nameof(owner)); | |
| _action = action ?? throw new ArgumentNullException(nameof(_action)); | |
| } | |
| internal void Notify() | |
| { | |
| if (!_disposed) | |
| { | |
| _action.Invoke(); | |
| } | |
| } | |
| public void Dispose() | |
| { | |
| if (!_disposed) | |
| { | |
| _disposed = true; | |
| _owner.Unsubscribe(this); | |
| GC.SuppressFinalize(this); | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment