@@ -47,8 +47,10 @@ namespace NLog.Internal
4747/// in the collection, and in positional order.
4848/// </summary>
4949[ DebuggerDisplay ( "Count = {Count}" ) ]
50- internal sealed class PropertiesDictionary : IDictionary < object , object ? > , IList < MessageTemplateParameter >
50+ internal sealed class PropertiesDictionary : IDictionary < object , object ? >
5151{
52+ const int SmallArraySize = 3 ;
53+
5254 private
5355#if! NETFRAMEWORK
5456readonly
@@ -99,7 +101,7 @@ public PropertiesDictionary(MessageTemplateParameter[]? messageParameters = null
99101/// </summary>
100102public PropertiesDictionary ( int initialCapacity )
101103{
102- if ( initialCapacity > 3 )
104+ if ( initialCapacity > SmallArraySize )
103105{
104106_eventProperties = new Dictionary < object , PropertyValue > ( initialCapacity , PropertyKeyComparer . Default ) ;
105107}
@@ -121,7 +123,7 @@ private Dictionary<object, PropertyValue> GetEventProperties(bool prepareForInse
121123return _eventProperties ;
122124}
123125
124- public IList < MessageTemplateParameter > MessageProperties => this ;
126+ public MessageTemplateParameter [ ] MessageProperties => ( _messageProperties is null || ( _messagePropertiesCount == SmallArraySize && _messageProperties [ 0 ] . CaptureType == CaptureType . Unknown ) ) ? ArrayHelper . Empty < MessageTemplateParameter > ( ) : _messageProperties ;
125127
126128public void ResetMessageProperties ( MessageTemplateParameter [ ] ? newMessageProperties = null , int newMessagePropertiesCount = 0 )
127129{
@@ -134,7 +136,7 @@ public void ResetMessageProperties(MessageTemplateParameter[]? newMessagePropert
134136{
135137eventProperties = _eventProperties = oldMessagePropertiesCount == 0 ?
136138new Dictionary < object , PropertyValue > ( newMessagePropertiesCount , PropertyKeyComparer . Default ) :
137- InitializeEventPropertiesDictionary ( false , oldMessageProperties , oldMessagePropertiesCount , out var _ ) ;
139+ InitializeEventPropertiesDictionary ( newMessagePropertiesCount > oldMessagePropertiesCount , oldMessageProperties , oldMessagePropertiesCount , out var _ ) ;
138140}
139141
140142if ( oldMessageProperties != null && eventProperties . Count > 0 )
@@ -146,13 +148,18 @@ public void ResetMessageProperties(MessageTemplateParameter[]? newMessagePropert
146148{
147149InsertMessagePropertiesIntoEmptyDictionary ( eventProperties , newMessageProperties , newMessagePropertiesCount , out _ ) ;
148150}
149- }
150151
151- _messageProperties = newMessageProperties ;
152- _messagePropertiesCount = newMessagePropertiesCount ;
152+ _messageProperties = newMessageProperties ;
153+ _messagePropertiesCount = newMessagePropertiesCount ;
154+ }
155+ else if ( newMessagePropertiesCount > 0 )
156+ {
157+ _messageProperties = newMessageProperties ;
158+ _messagePropertiesCount = newMessagePropertiesCount ;
159+ }
153160}
154161
155- private static void RemoveOldMessageProperties ( Dictionary < object , PropertyValue > eventProperties , IList < MessageTemplateParameter > oldMessageProperties , int oldMessagePropertiesCount )
162+ private static void RemoveOldMessageProperties ( Dictionary < object , PropertyValue > eventProperties , MessageTemplateParameter [ ] oldMessageProperties , int oldMessagePropertiesCount )
156163{
157164for ( int i = 0 ; i < oldMessagePropertiesCount ; ++ i )
158165{
@@ -165,7 +172,7 @@ private static void RemoveOldMessageProperties(Dictionary<object, PropertyValue>
165172
166173private static Dictionary < object , PropertyValue > InitializeEventPropertiesDictionary ( bool prepareForInsert , MessageTemplateParameter [ ] ? messageProperties , int messagePropertiesCount , out bool resetMessageProperties )
167174{
168- if ( messageProperties != null && messagePropertiesCount > 0 )
175+ if ( messagePropertiesCount > 0 && messageProperties != null )
169176{
170177var dictionaryCapacity = prepareForInsert ? ( messagePropertiesCount + 2 ) : messagePropertiesCount ;
171178var eventProperties = new Dictionary < object , PropertyValue > ( dictionaryCapacity , PropertyKeyComparer . Default ) ;
@@ -195,26 +202,6 @@ private static Dictionary<object, PropertyValue> InitializeEventPropertiesDictio
195202/// <inheritDoc/>
196203public bool IsReadOnly => false ;
197204
198- int ICollection < MessageTemplateParameter > . Count => _messagePropertiesCount ;
199-
200- bool ICollection < MessageTemplateParameter > . IsReadOnly => true ;
201-
202- MessageTemplateParameter IList < MessageTemplateParameter > . this [ int index ]
203- {
204- get
205- {
206- if ( index >= _messagePropertiesCount || index < 0 || _messageProperties is null )
207- throw new ArgumentOutOfRangeException ( nameof ( index ) ) ;
208- return _messageProperties [ index ] ;
209- }
210- set
211- {
212- if ( index >= _messagePropertiesCount || index < 0 || _messageProperties is null )
213- throw new ArgumentOutOfRangeException ( nameof ( index ) ) ;
214- _messageProperties [ index ] = value ;
215- }
216- }
217-
218205/// <inheritDoc/>
219206public object ? this [ object key ]
220207{
@@ -231,16 +218,7 @@ public object? this[object key]
231218{
232219if ( SkipDictionaryAllocation ( ) && key is string propertyName && propertyName . Length > 0 )
233220{
234- var messageProperties = _messageProperties ?? ( _messageProperties = new MessageTemplateParameter [ 3 ] ) ;
235- for ( int i = 0 ; i < _messagePropertiesCount ; ++ i )
236- {
237- if ( messageProperties [ i ] . Name . Equals ( propertyName ) )
238- {
239- messageProperties [ i ] = new MessageTemplateParameter ( messageProperties [ i ] . Name , value , messageProperties [ i ] . Format , messageProperties [ i ] . CaptureType ) ;
240- return ;
241- }
242- }
243- messageProperties [ _messagePropertiesCount ++ ] = new MessageTemplateParameter ( propertyName , value , null , CaptureType . Unknown ) ;
221+ AddOrUpdateMessageProperties ( propertyName , value , true ) ;
244222return ;
245223}
246224
@@ -253,26 +231,13 @@ public void Add(object key, object? value)
253231{
254232if ( SkipDictionaryAllocation ( ) && key is string propertyName && propertyName . Length > 0 )
255233{
256- var messageProperties = _messageProperties ?? ( _messageProperties = new MessageTemplateParameter [ 3 ] ) ;
257- for ( int i = 0 ; i < _messagePropertiesCount ; ++ i )
258- {
259- if ( messageProperties [ i ] . Name . Equals ( propertyName ) )
260- {
261- throw new ArgumentException ( $ "An item with the same key{ propertyName } has already been added.", nameof ( key ) ) ;
262- }
263- }
264- messageProperties [ _messagePropertiesCount ++ ] = new MessageTemplateParameter ( propertyName , value , null , CaptureType . Unknown ) ;
234+ AddOrUpdateMessageProperties ( propertyName , value , false ) ;
265235return ;
266236}
267237
268238GetEventProperties ( true ) [ key ] = new PropertyValue ( value , false ) ;
269239}
270240
271- private bool SkipDictionaryAllocation ( )
272- {
273- return _eventProperties is null && ( _messageProperties is null || _messagePropertiesCount < _messageProperties . Length ) ;
274- }
275-
276241/// <inheritDoc/>
277242public void Add ( KeyValuePair < object , object ? > item )
278243{
@@ -370,18 +335,15 @@ public bool Remove(KeyValuePair<object, object?> item)
370335/// <inheritDoc/>
371336public bool TryGetValue ( object key , out object ? value )
372337{
373- if ( ! IsEmpty )
338+ if ( _eventProperties is null )
374339{
375- if ( _eventProperties is null )
376- {
377- return TryLookupMessagePropertyValue ( key , out value ) ;
378- }
340+ return TryLookupMessagePropertyValue ( key , out value ) ;
341+ }
379342
380- if ( _eventProperties . TryGetValue ( key , out var eventProperty ) )
381- {
382- value = eventProperty . Value ;
383- return true ;
384- }
343+ if ( _eventProperties . TryGetValue ( key , out var eventProperty ) )
344+ {
345+ value = eventProperty . Value ;
346+ return true ;
385347}
386348
387349value = null ;
@@ -431,6 +393,30 @@ private bool TryLookupMessagePropertyValue(object key, out object? propertyValue
431393return false ;
432394}
433395
396+ private void AddOrUpdateMessageProperties ( string propertyName , object ? value , bool allowUpdate )
397+ {
398+ var messageProperties = _messageProperties ?? ( _messageProperties = new MessageTemplateParameter [ SmallArraySize ] ) ;
399+ for ( int i = 0 ; i < _messagePropertiesCount ; ++ i )
400+ {
401+ if ( propertyName . Equals ( messageProperties [ i ] . Name ) )
402+ {
403+ if ( ! allowUpdate )
404+ {
405+ throw new ArgumentException ( $ "An item with the same key{ propertyName } has already been added.", nameof ( propertyName ) ) ;
406+ }
407+ messageProperties [ i ] = new MessageTemplateParameter ( propertyName , value , null , CaptureType . Unknown ) ;
408+ return ;
409+ }
410+ }
411+
412+ messageProperties [ _messagePropertiesCount ++ ] = new MessageTemplateParameter ( propertyName , value , null , CaptureType . Unknown ) ;
413+ }
414+
415+ private bool SkipDictionaryAllocation ( )
416+ {
417+ return _eventProperties is null && ( _messageProperties is null || _messagePropertiesCount < _messageProperties . Length ) ;
418+ }
419+
434420/// <summary>
435421/// Check if the message-template-parameters can be used directly without allocating a dictionary
436422/// </summary>
@@ -513,65 +499,6 @@ internal static string GenerateUniquePropertyName<TKey, TValue>(string originalN
513499return newItemName ;
514500}
515501
516- int IList < MessageTemplateParameter > . IndexOf ( MessageTemplateParameter item )
517- {
518- if ( _messageProperties != null && _messagePropertiesCount > 0 )
519- {
520- for ( int i = 0 ; i < _messagePropertiesCount ; ++ i )
521- {
522- if ( _messageProperties [ i ] . Equals ( item ) )
523- return i ;
524- }
525- }
526- return - 1 ;
527- }
528-
529- bool ICollection < MessageTemplateParameter > . Contains ( MessageTemplateParameter item )
530- {
531- return ( ( IList < MessageTemplateParameter > ) this ) . IndexOf ( item ) >= 0 ;
532- }
533-
534- void ICollection < MessageTemplateParameter > . CopyTo ( MessageTemplateParameter [ ] array , int arrayIndex )
535- {
536- if ( _messageProperties != null && _messagePropertiesCount > 0 )
537- {
538- Array . Copy ( _messageProperties , 0 , array , arrayIndex , _messagePropertiesCount ) ;
539- }
540- }
541-
542- void IList < MessageTemplateParameter > . Insert ( int index , MessageTemplateParameter item )
543- {
544- throw new NotSupportedException ( "MessageTemplateParameters array is read-only" ) ;
545- }
546-
547- void IList < MessageTemplateParameter > . RemoveAt ( int index )
548- {
549- throw new NotSupportedException ( "MessageTemplateParameters array is read-only" ) ;
550- }
551-
552- void ICollection < MessageTemplateParameter > . Add ( MessageTemplateParameter item )
553- {
554- throw new NotSupportedException ( "MessageTemplateParameters array is read-only" ) ;
555- }
556-
557- void ICollection < MessageTemplateParameter > . Clear ( )
558- {
559- throw new NotSupportedException ( "MessageTemplateParameters array is read-only" ) ;
560- }
561-
562- bool ICollection < MessageTemplateParameter > . Remove ( MessageTemplateParameter item )
563- {
564- throw new NotSupportedException ( "MessageTemplateParameters array is read-only" ) ;
565- }
566-
567- IEnumerator < MessageTemplateParameter > IEnumerable < MessageTemplateParameter > . GetEnumerator ( )
568- {
569- if ( _messageProperties is null )
570- return System . Linq . Enumerable . Empty < MessageTemplateParameter > ( ) . GetEnumerator ( ) ;
571- else
572- return ( ( IList < MessageTemplateParameter > ) _messageProperties ) . GetEnumerator ( ) ;
573- }
574-
575502public struct PropertyDictionaryEnumerator : IEnumerator < KeyValuePair < object , object ? > >
576503{
577504private readonly PropertiesDictionary _dictionary ;
@@ -699,7 +626,7 @@ public void Dispose()
699626public void Reset ( )
700627{
701628_messagePropertiesIndex = _dictionary . _messagePropertiesCount > 0 ? - 1 : default ( int ? ) ;
702- _eventEnumerator = default ( Dictionary < object , PropertyValue > . Enumerator ) ;
629+ _eventEnumerator = _dictionary . _eventProperties ? . GetEnumerator ( ) ?? default ( Dictionary < object , PropertyValue > . Enumerator ) ;
703630}
704631}
705632