Skip to content

Instantly share code, notes, and snippets.

@jasonswearingen
Created January 26, 2023 16:27
Show Gist options
  • Save jasonswearingen/9716477d113a7d6551885c85850960d4 to your computer and use it in GitHub Desktop.
Save jasonswearingen/9716477d113a7d6551885c85850960d4 to your computer and use it in GitHub Desktop.
C# Event abstraction
/// <summary>
/// thread safe event registration and invoking.
/// subscriptions are stored as weakRefs so they can be garbage collected.
/// </summary>
/// <typeparam name="TEventArgs"></typeparam>
public class Event<TEventArgs> where TEventArgs : EventArgs
{
private List<WeakReference<EventHandler<TEventArgs>>> _storage = new();
/// <summary>
/// used in enumration when .Invoke() is called.
/// </summary>
private List<WeakReference<EventHandler<TEventArgs>>> _storageTempCopy = new();
/// <summary>
/// (un)subscribe here
/// </summary>
public event EventHandler<TEventArgs> Handler
{
add
{
//my custom assert framework. can just comment these out.
__.assert.IsFalse(isDisposed);
lock (_storage)
{
_storage.Add(new WeakReference<EventHandler<TEventArgs>>(value));
}
}
remove
{
__.assert.IsFalse(isDisposed);
lock (_storage)
{
_storage._RemoveLast(x => x.TryGetTarget(out var target) && target == value);
}
}
}
/// <summary>
/// only the owner should call this
/// </summary>
public void Invoke(object sender, TEventArgs args)
{
__.assert.IsFalse(isDisposed);
lock (_storage)
{
__.assert.IsTrue(_storageTempCopy.Count == 0);
_storageTempCopy.AddRange(_storage);
}
var anyExpired = false;
foreach (var weakRef in _storageTempCopy)
{
if (weakRef.TryGetTarget(out var handler))
{
handler(sender, args);
}
else
{
anyExpired = true;
}
}
if (anyExpired)
{
_RemoveExpiredSubscriptions();
}
_storageTempCopy.Clear();
__.assert.IsFalse(isDisposed);
}
private void _RemoveExpiredSubscriptions()
{
lock (_storage)
{
//remove all expired weakrefs
_storage.RemoveAll(weakRef => weakRef.TryGetTarget(out _) == false);
}
}
////dispose removed as not needed (using weak ref)
//private bool isDisposed;
//public void Dispose()
//{
// isDisposed = true;
// _storageTempCopy.Clear();
// _storage.Clear();
//}
}
public class Event : Event<EventArgs>
{
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment