@@ -24,26 +24,28 @@ public sealed class Messenger : IMessenger
24
24
// --------------------------------------------------------------------------------------------------------
25
25
// DictionarySlim<Recipient, HashSet<IMapping>> recipientsMap;
26
26
// | \________________[*]IDictionarySlim<Recipient, IDictionarySlim<TToken>>
27
- // | \___ / / /
28
- // | ________(recipients registrations)___________\________ / / __ /
29
- // | / _______(channel registrations)_____\___________________/ /
30
- // | / / \ /
31
- // DictionarySlim<Recipient, DictionarySlim<TToken, MessageHandler<object , TMessage>>> mapping = Mapping<TMessage, TToken>
32
- // / / \ / /
33
- // ___(Type2.tToken)____/ / \______/_________________________ /
34
- // /________________(Type2.tMessage)____ / /
35
- // / ________________________________________ /
27
+ // | \____________/_________ /
28
+ // | ________(recipients registrations)____________________ / \ /
29
+ // | / ____(channel registrations)________________\____________ /
30
+ // | / / \
31
+ // DictionarySlim<Recipient, DictionarySlim<TToken, MessageHandler<TRecipient , TMessage>>> mapping = Mapping<TMessage, TToken>
32
+ // / / /
33
+ // ___(Type2.tToken)____/ / /
34
+ // /________________(Type2.tMessage)________________________ / /
35
+ // / ____________________________________________________________ /
36
36
// / /
37
37
// DictionarySlim<Type2, IMapping> typesMap;
38
38
// --------------------------------------------------------------------------------------------------------
39
39
// Each combination of <TMessage, TToken> results in a concrete Mapping<TMessage, TToken> type, which holds the references
40
- // from registered recipients to handlers. The handlers are stored in a <TToken, MessageHandler<object, TMessage>>
41
- // dictionary, so that each recipient can have up to one registered handler for a given token, for each message type.
42
- // Note that the registered handlers are unsafe-cast to a MessageHandler<object, TMessage> instance even if they were
43
- // actually of type MessageHandler<TRecipient, TMessage>. This allows the messenger to track and invoke type-specific
44
- // handlers without using reflection and without having to capture the input handler in a proxy delegate, causing one
45
- // extra memory allocations and adding overhead. The type conversion is guaranteed to be respected due to how the
46
- // messenger type itself works - as registered handlers are always invoked on their respective recipients.
40
+ // from registered recipients to handlers. The handlers are stored in a <TToken, MessageHandler<object, TMessage>> dictionary,
41
+ // so that each recipient can have up to one registered handler for a given token, for each message type.
42
+ // Note that the registered handlers are only stored as object references, even if they were actually of type
43
+ // MessageHandler<TRecipient, TMessage>, to avoid unnecessary unsafe casts. Each handler is also generic with respect to the
44
+ // recipient type, in order to allow the messenger to track and invoke type-specific handlers without using reflection and
45
+ // without having to capture the input handler in a proxy delegate, causing one extra memory allocations and adding overhead.
46
+ // This allows users to retain type information on each registered recipient, instead of having to manually cast each recipient
47
+ // to the right type within the handler. The type conversion is guaranteed to be respected due to how the messenger type
48
+ // itself works - as registered handlers are always invoked on their respective recipients.
47
49
// Each mapping is stored in the types map, which associates each pair of concrete types to its
48
50
// mapping instance. Mapping instances are exposed as IMapping items, as each will be a closed type over
49
51
// a different combination of TMessage and TToken generic type parameters. Each existing recipient is also stored in
@@ -114,20 +116,20 @@ public void Register<TRecipient, TMessage, TToken>(TRecipient recipient, TToken
114
116
// Get the <TMessage, TToken> registration list for this recipient
115
117
Mapping < TMessage , TToken > mapping = GetOrAddMapping < TMessage , TToken > ( ) ;
116
118
var key = new Recipient ( recipient ) ;
117
- ref DictionarySlim < TToken , MessageHandler < object , TMessage > > ? map = ref mapping . GetOrAddValueRef ( key ) ;
119
+ ref DictionarySlim < TToken , object > ? map = ref mapping . GetOrAddValueRef ( key ) ;
118
120
119
- map ??= new DictionarySlim < TToken , MessageHandler < object , TMessage > > ( ) ;
121
+ map ??= new DictionarySlim < TToken , object > ( ) ;
120
122
121
123
// Add the new registration entry
122
- ref MessageHandler < object , TMessage > ? registeredHandler = ref map . GetOrAddValueRef ( token ) ;
124
+ ref object ? registeredHandler = ref map . GetOrAddValueRef ( token ) ;
123
125
124
126
if ( ! ( registeredHandler is null ) )
125
127
{
126
128
ThrowInvalidOperationExceptionForDuplicateRegistration ( ) ;
127
129
}
128
130
129
131
// Treat the input delegate as if it was covariant (see comments below in the Send method)
130
- registeredHandler = Unsafe . As < MessageHandler < object , TMessage > > ( handler ) ;
132
+ registeredHandler = handler ;
131
133
132
134
// Update the total counter for handlers for the current type parameters
133
135
mapping . TotalHandlersCount ++ ;
@@ -325,7 +327,7 @@ public void Unregister<TMessage, TToken>(object recipient, TToken token)
325
327
326
328
var key = new Recipient ( recipient ) ;
327
329
328
- if ( ! mapping ! . TryGetValue ( key , out DictionarySlim < TToken , MessageHandler < object , TMessage > > ? dictionary ) )
330
+ if ( ! mapping ! . TryGetValue ( key , out DictionarySlim < TToken , object > ? dictionary ) )
329
331
{
330
332
return ;
331
333
}
@@ -533,7 +535,7 @@ private Mapping<TMessage, TToken> GetOrAddMapping<TMessage, TToken>()
533
535
/// This type is defined for simplicity and as a workaround for the lack of support for using type aliases
534
536
/// over open generic types in C# (using type aliases can only be used for concrete, closed types).
535
537
/// </remarks>
536
- private sealed class Mapping < TMessage , TToken > : DictionarySlim < Recipient , DictionarySlim < TToken , MessageHandler < object , TMessage > > > , IMapping
538
+ private sealed class Mapping < TMessage , TToken > : DictionarySlim < Recipient , DictionarySlim < TToken , object > > , IMapping
537
539
where TMessage : class
538
540
where TToken : IEquatable < TToken >
539
541
{
0 commit comments