Created
January 26, 2023 16:27
-
-
Save jasonswearingen/9716477d113a7d6551885c85850960d4 to your computer and use it in GitHub Desktop.
C# Event abstraction
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
/// <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