Skip to content

Commit 137c6bd

Browse files
committed
Code refactoring to StrongReferenceMessenger
1 parent 0bc0648 commit 137c6bd

File tree

1 file changed

+14
-13
lines changed

1 file changed

+14
-13
lines changed

Microsoft.Toolkit.Mvvm/Messaging/StrongReferenceMessenger.cs

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,8 @@ public TMessage Send<TMessage, TToken>(TMessage message, TToken token)
329329
where TMessage : class
330330
where TToken : IEquatable<TToken>
331331
{
332-
Object2[] pairs;
332+
object[] rentedArray;
333+
Span<object> pairs;
333334
int i = 0;
334335

335336
lock (this.recipientsMap)
@@ -355,7 +356,9 @@ public TMessage Send<TMessage, TToken>(TMessage message, TToken token)
355356
return message;
356357
}
357358

358-
pairs = ArrayPool<Object2>.Shared.Rent(totalHandlersCount);
359+
// Rent the array and also assign it to a span, which will be used to access values.
360+
// We're doing this to avoid the array covariance checks slowdown in the loops below.
361+
pairs = rentedArray = ArrayPool<object>.Shared.Rent(2 * totalHandlersCount);
359362

360363
// Copy the handlers to the local collection.
361364
// The array is oversized at this point, since it also includes
@@ -373,39 +376,37 @@ public TMessage Send<TMessage, TToken>(TMessage message, TToken token)
373376
// Pick the target handler, if the token is a match for the recipient
374377
if (mappingEnumerator.Value.TryGetValue(token, out object? handler))
375378
{
376-
// This array access should always guaranteed to be valid due to the size of the
379+
// This span access should always guaranteed to be valid due to the size of the
377380
// array being set according to the current total number of registered handlers,
378381
// which will always be greater or equal than the ones matching the previous test.
379-
// We're still using a checked array access here though to make sure an out of
382+
// We're still using a checked span accesses here though to make sure an out of
380383
// bounds write can never happen even if an error was present in the logic above.
381-
pairs[i++] = new Object2(handler!, recipient);
384+
pairs[2 * i] = handler!;
385+
pairs[(2 * i) + 1] = recipient;
386+
i++;
382387
}
383388
}
384389
}
385390

386-
// The rented array is often larger than the number of matching pairs
387-
// to process, so we first slice the span with just the items we need.
388-
Span<Object2> pendingPairs = pairs.AsSpan(0, i);
389-
390391
try
391392
{
392393
// Invoke all the necessary handlers on the local copy of entries
393-
foreach (ref Object2 pair in pendingPairs)
394+
for (int j = 0; j < i; j++)
394395
{
395396
// Here we perform an unsafe cast to enable covariance for delegate types.
396397
// We know that the input recipient will always respect the type constraints
397398
// of each original input delegate, and doing so allows us to still invoke
398399
// them all from here without worrying about specific generic type arguments.
399-
Unsafe.As<MessageHandler<object, TMessage>>(pair.Handler)(pair.Recipient, message);
400+
Unsafe.As<MessageHandler<object, TMessage>>(pairs[2 * j])(pairs[(2 * j) + 1], message);
400401
}
401402
}
402403
finally
403404
{
404405
// As before, we also need to clear it first to avoid having potentially long
405406
// lasting memory leaks due to leftover references being stored in the pool.
406-
pendingPairs.Clear();
407+
Array.Clear(rentedArray, 0, 2 * i);
407408

408-
ArrayPool<Object2>.Shared.Return(pairs);
409+
ArrayPool<object>.Shared.Return(rentedArray);
409410
}
410411

411412
return message;

0 commit comments

Comments
 (0)