Skip to content

Commit 3293fa6

Browse files
committed
Minor code refactoring
1 parent af91276 commit 3293fa6

File tree

1 file changed

+24
-22
lines changed

1 file changed

+24
-22
lines changed

Microsoft.Toolkit.Mvvm/Messaging/Messenger.cs

Lines changed: 24 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -24,26 +24,28 @@ public sealed class Messenger : IMessenger
2424
// --------------------------------------------------------------------------------------------------------
2525
// DictionarySlim<Recipient, HashSet<IMapping>> recipientsMap;
2626
// | \________________[*]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+
// / ____________________________________________________________/
3636
// / /
3737
// DictionarySlim<Type2, IMapping> typesMap;
3838
// --------------------------------------------------------------------------------------------------------
3939
// 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.
4749
// Each mapping is stored in the types map, which associates each pair of concrete types to its
4850
// mapping instance. Mapping instances are exposed as IMapping items, as each will be a closed type over
4951
// 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
114116
// Get the <TMessage, TToken> registration list for this recipient
115117
Mapping<TMessage, TToken> mapping = GetOrAddMapping<TMessage, TToken>();
116118
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);
118120

119-
map ??= new DictionarySlim<TToken, MessageHandler<object, TMessage>>();
121+
map ??= new DictionarySlim<TToken, object>();
120122

121123
// Add the new registration entry
122-
ref MessageHandler<object, TMessage>? registeredHandler = ref map.GetOrAddValueRef(token);
124+
ref object? registeredHandler = ref map.GetOrAddValueRef(token);
123125

124126
if (!(registeredHandler is null))
125127
{
126128
ThrowInvalidOperationExceptionForDuplicateRegistration();
127129
}
128130

129131
// 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;
131133

132134
// Update the total counter for handlers for the current type parameters
133135
mapping.TotalHandlersCount++;
@@ -325,7 +327,7 @@ public void Unregister<TMessage, TToken>(object recipient, TToken token)
325327

326328
var key = new Recipient(recipient);
327329

328-
if (!mapping!.TryGetValue(key, out DictionarySlim<TToken, MessageHandler<object, TMessage>>? dictionary))
330+
if (!mapping!.TryGetValue(key, out DictionarySlim<TToken, object>? dictionary))
329331
{
330332
return;
331333
}
@@ -533,7 +535,7 @@ private Mapping<TMessage, TToken> GetOrAddMapping<TMessage, TToken>()
533535
/// This type is defined for simplicity and as a workaround for the lack of support for using type aliases
534536
/// over open generic types in C# (using type aliases can only be used for concrete, closed types).
535537
/// </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
537539
where TMessage : class
538540
where TToken : IEquatable<TToken>
539541
{

0 commit comments

Comments
 (0)