From cad048def3025c72c6c9a940e82eb335bf9a7b4f Mon Sep 17 00:00:00 2001 From: Enderlook Date: Tue, 12 Apr 2022 18:08:20 -0300 Subject: [PATCH] Fix callbacks that listen to derived event types not being raised unless the derived type has at least one subscribed callback Implementation for GH-1. --- CHANGELOG.md | 4 +++ .../Enderlook.EventManager.csproj | 2 +- Enderlook.EventManager/src/EventManager.cs | 30 +++++++++++-------- 3 files changed, 23 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e81665..ed249e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## 0.4.1 + +- Fix callbacks that listen to derived event types not being raised unless the derived type has at least one subscribed callback. + ## 0.4.0 - Increase performance on weak handles. diff --git a/Enderlook.EventManager/Enderlook.EventManager.csproj b/Enderlook.EventManager/Enderlook.EventManager.csproj index 4659647..ee54fd4 100644 --- a/Enderlook.EventManager/Enderlook.EventManager.csproj +++ b/Enderlook.EventManager/Enderlook.EventManager.csproj @@ -10,7 +10,7 @@ Enderlook.EventManager https://github.com/Enderlook/Net-Event-Manager git - 0.4.0 + 0.4.1 true true 10 diff --git a/Enderlook.EventManager/src/EventManager.cs b/Enderlook.EventManager/src/EventManager.cs index f7b961c..dbda1ca 100644 --- a/Enderlook.EventManager/src/EventManager.cs +++ b/Enderlook.EventManager/src/EventManager.cs @@ -54,8 +54,11 @@ public void Raise(TEvent argument) manager_.StaticRaise(argument, this); } else - ReadEnd(); + SlowPath(); } + + [MethodImpl(MethodImplOptions.NoInlining)] + void SlowPath() => CreateInvokersHolderManager().StaticRaise(argument, this); } /// @@ -76,8 +79,11 @@ public void Raise(TEvent argument) manager_.StaticRaise(new TEvent(), this); } else - ReadEnd(); + SlowPath(); } + + [MethodImpl(MethodImplOptions.NoInlining)] + void SlowPath() => CreateInvokersHolderManager().StaticRaise(new TEvent(), this); } /// @@ -97,9 +103,10 @@ public void Raise(TEvent argument) /// Thrown when this instance has already been disposed. public void DynamicRaise(TEvent argument) { + Type key = argument?.GetType() ?? typeof(TEvent); ReadBegin(); { - if (managersPerType.TryGetValue(argument?.GetType() ?? typeof(TEvent), out InvokersHolderManager? manager)) + if (managersPerType.TryGetValue(key, out InvokersHolderManager? manager)) { FromReadToInHolder(); // TODO: This virtual call is actually only required if argument.GetType().IsValueType @@ -107,8 +114,11 @@ public void DynamicRaise(TEvent argument) manager.DynamicRaise(argument, this); } else - ReadEnd(); + SlowPath(); } + + [MethodImpl(MethodImplOptions.NoInlining)] + void SlowPath() => CreateInvokersHolderManagerDynamic(key).DynamicRaise(argument, this); } internal void Unsubscribe(TPredicator predicator, bool listenToAssignableEvents) @@ -254,15 +264,12 @@ private InvokersHolderManager CreateInvokersHolderManagerDynamic(Type type) } [MethodImpl(MethodImplOptions.NoInlining)] - private InvokersHolderManager CreateInvokersHolderManager() + private InvokersHolderManager CreateInvokersHolderManager() { InvokersHolderManager? manager; FromReadToWrite(); { - ref InvokersHolderManager slot = ref managersPerType.GetOrCreateValueSlot(typeof(TEvent), out bool found); - if (found) - manager = slot; - else + if (!managersPerType.TryGetValue(typeof(TEvent), out manager)) { manager = new InvokersHolderManager(); @@ -278,12 +285,11 @@ private InvokersHolderManager CreateInvokersHolderManager() } } } - - slot = manager; + managersPerType.Add(typeof(TEvent), manager); } } FromWriteToInHolder(); - return manager; + return Utils.ExpectExactType>(manager); } [DoesNotReturn]