55using System ;
66using System . Buffers ;
77using System . Collections . Generic ;
8+ using System . Diagnostics . Contracts ;
89using System . Runtime . CompilerServices ;
910using Microsoft . Collections . Extensions ;
1011using Microsoft . Toolkit . Mvvm . Messaging . Internals ;
@@ -181,8 +182,8 @@ public TMessage Send<TMessage, TToken>(TMessage message, TToken token)
181182 return message ;
182183 }
183184
184- recipients = new ArrayPoolBufferWriter < object > ( ) ;
185- handlers = new ArrayPoolBufferWriter < object > ( ) ;
185+ recipients = ArrayPoolBufferWriter < object > . Create ( ) ;
186+ handlers = ArrayPoolBufferWriter < object > . Create ( ) ;
186187
187188 // We need a local, temporary copy of all the pending recipients and handlers to
188189 // invoke, to avoid issues with handlers unregistering from messages while we're
@@ -232,8 +233,8 @@ public void Cleanup()
232233 {
233234 lock ( this . recipientsMap )
234235 {
235- using ArrayPoolBufferWriter < Type2 > type2s = new ArrayPoolBufferWriter < Type2 > ( ) ;
236- using ArrayPoolBufferWriter < object > emptyRecipients = new ArrayPoolBufferWriter < object > ( ) ;
236+ using ArrayPoolBufferWriter < Type2 > type2s = ArrayPoolBufferWriter < Type2 > . Create ( ) ;
237+ using ArrayPoolBufferWriter < object > emptyRecipients = ArrayPoolBufferWriter < object > . Create ( ) ;
237238
238239 var enumerator = this . recipientsMap . GetEnumerator ( ) ;
239240
@@ -385,7 +386,12 @@ public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
385386 /// A simple buffer writer implementation using pooled arrays.
386387 /// </summary>
387388 /// <typeparam name="T">The type of items to store in the list.</typeparam>
388- private sealed class ArrayPoolBufferWriter < T > : IDisposable
389+ /// <remarks>
390+ /// This type is a <see langword="ref"/> <see langword="struct"/> to avoid the object allocation and to
391+ /// enable the pattern-based <see cref="IDisposable"/> support. We aren't worried with consumers not
392+ /// using this type correctly since it's private and only accessible within the parent type.
393+ /// </remarks>
394+ private ref struct ArrayPoolBufferWriter < T >
389395 {
390396 /// <summary>
391397 /// The default buffer size to use to expand empty arrays.
@@ -403,12 +409,13 @@ private sealed class ArrayPoolBufferWriter<T> : IDisposable
403409 private int index ;
404410
405411 /// <summary>
406- /// Initializes a new instance of the <see cref="ArrayPoolBufferWriter{T}"/> class .
412+ /// Creates a new instance of the <see cref="ArrayPoolBufferWriter{T}"/> struct .
407413 /// </summary>
408- public ArrayPoolBufferWriter ( )
414+ [ Pure ]
415+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
416+ public static ArrayPoolBufferWriter < T > Create ( )
409417 {
410- this . array = ArrayPool < T > . Shared . Rent ( DefaultInitialBufferSize ) ;
411- this . index = 0 ;
418+ return new ArrayPoolBufferWriter < T > { array = ArrayPool < T > . Shared . Rent ( DefaultInitialBufferSize ) } ;
412419 }
413420
414421 /// <summary>
@@ -461,7 +468,7 @@ private void ResizeBuffer()
461468 this . array = rent ;
462469 }
463470
464- /// <inheritdoc/>
471+ /// <inheritdoc cref="IDisposable.Dispose" />
465472 public void Dispose ( )
466473 {
467474 Array . Clear ( this . array , 0 , this . index ) ;
0 commit comments