@@ -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 || ( _messageProperties . Length == 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{
@@ -229,48 +216,14 @@ public object? this[object key]
229216}
230217set
231218{
232- if ( SkipDictionaryAllocation ( ) && key is string propertyName && propertyName . Length > 0 )
233- {
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 ) ;
244- return ;
245- }
246-
247- GetEventProperties ( true ) [ key ] = new PropertyValue ( value , false ) ;
219+ AddOrUpdateMessageProperties ( key , value , true ) ;
248220}
249221}
250222
251223/// <inheritDoc/>
252224public void Add ( object key , object ? value )
253225{
254- if ( SkipDictionaryAllocation ( ) && key is string propertyName && propertyName . Length > 0 )
255- {
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 ) ;
265- return ;
266- }
267-
268- GetEventProperties ( true ) [ key ] = new PropertyValue ( value , false ) ;
269- }
270-
271- private bool SkipDictionaryAllocation ( )
272- {
273- return _eventProperties is null && ( _messageProperties is null || _messagePropertiesCount < _messageProperties . Length ) ;
226+ AddOrUpdateMessageProperties ( key , value , false ) ;
274227}
275228
276229/// <inheritDoc/>
@@ -428,6 +381,41 @@ private bool TryLookupMessagePropertyValue(object key, out object? propertyValue
428381return false ;
429382}
430383
384+ private void AddOrUpdateMessageProperties ( object key , object ? value , bool allowUpdate )
385+ {
386+ if ( SkipDictionaryAllocation ( ) && key is string propertyName && propertyName . Length > 0 )
387+ {
388+ var messageProperties = _messageProperties ?? ( _messageProperties = new MessageTemplateParameter [ SmallArraySize ] ) ;
389+ for ( int i = 0 ; i < _messagePropertiesCount ; ++ i )
390+ {
391+ if ( propertyName . Equals ( messageProperties [ i ] . Name ) )
392+ {
393+ if ( ! allowUpdate )
394+ {
395+ throw new ArgumentException ( $ "An item with the same key{ propertyName } has already been added.", nameof ( key ) ) ;
396+ }
397+ messageProperties [ i ] = new MessageTemplateParameter ( propertyName , value , null , CaptureType . Unknown ) ;
398+ return ;
399+ }
400+ }
401+
402+ messageProperties [ _messagePropertiesCount ++ ] = new MessageTemplateParameter ( propertyName , value , null , CaptureType . Unknown ) ;
403+ }
404+ else if ( allowUpdate )
405+ {
406+ GetEventProperties ( true ) [ key ] = new PropertyValue ( value , false ) ;
407+ }
408+ else
409+ {
410+ GetEventProperties ( true ) . Add ( key , new PropertyValue ( value , false ) ) ;
411+ }
412+ }
413+
414+ private bool SkipDictionaryAllocation ( )
415+ {
416+ return _eventProperties is null && ( _messageProperties is null || _messagePropertiesCount < _messageProperties . Length ) ;
417+ }
418+
431419/// <summary>
432420/// Check if the message-template-parameters can be used directly without allocating a dictionary
433421/// </summary>
@@ -510,65 +498,6 @@ internal static string GenerateUniquePropertyName<TKey, TValue>(string originalN
510498return newItemName ;
511499}
512500
513- int IList < MessageTemplateParameter > . IndexOf ( MessageTemplateParameter item )
514- {
515- if ( _messageProperties != null && _messagePropertiesCount > 0 )
516- {
517- for ( int i = 0 ; i < _messagePropertiesCount ; ++ i )
518- {
519- if ( _messageProperties [ i ] . Equals ( item ) )
520- return i ;
521- }
522- }
523- return - 1 ;
524- }
525-
526- bool ICollection < MessageTemplateParameter > . Contains ( MessageTemplateParameter item )
527- {
528- return ( ( IList < MessageTemplateParameter > ) this ) . IndexOf ( item ) >= 0 ;
529- }
530-
531- void ICollection < MessageTemplateParameter > . CopyTo ( MessageTemplateParameter [ ] array , int arrayIndex )
532- {
533- if ( _messageProperties != null && _messagePropertiesCount > 0 )
534- {
535- Array . Copy ( _messageProperties , 0 , array , arrayIndex , _messagePropertiesCount ) ;
536- }
537- }
538-
539- void IList < MessageTemplateParameter > . Insert ( int index , MessageTemplateParameter item )
540- {
541- throw new NotSupportedException ( "MessageTemplateParameters array is read-only" ) ;
542- }
543-
544- void IList < MessageTemplateParameter > . RemoveAt ( int index )
545- {
546- throw new NotSupportedException ( "MessageTemplateParameters array is read-only" ) ;
547- }
548-
549- void ICollection < MessageTemplateParameter > . Add ( MessageTemplateParameter item )
550- {
551- throw new NotSupportedException ( "MessageTemplateParameters array is read-only" ) ;
552- }
553-
554- void ICollection < MessageTemplateParameter > . Clear ( )
555- {
556- throw new NotSupportedException ( "MessageTemplateParameters array is read-only" ) ;
557- }
558-
559- bool ICollection < MessageTemplateParameter > . Remove ( MessageTemplateParameter item )
560- {
561- throw new NotSupportedException ( "MessageTemplateParameters array is read-only" ) ;
562- }
563-
564- IEnumerator < MessageTemplateParameter > IEnumerable < MessageTemplateParameter > . GetEnumerator ( )
565- {
566- if ( _messageProperties is null )
567- return System . Linq . Enumerable . Empty < MessageTemplateParameter > ( ) . GetEnumerator ( ) ;
568- else
569- return ( ( IList < MessageTemplateParameter > ) _messageProperties ) . GetEnumerator ( ) ;
570- }
571-
572501public struct PropertyDictionaryEnumerator : IEnumerator < KeyValuePair < object , object ? > >
573502{
574503private readonly PropertiesDictionary _dictionary ;
@@ -696,7 +625,7 @@ public void Dispose()
696625public void Reset ( )
697626{
698627_messagePropertiesIndex = _dictionary . _messagePropertiesCount > 0 ? - 1 : default ( int ? ) ;
699- _eventEnumerator = default ( Dictionary < object , PropertyValue > . Enumerator ) ;
628+ _eventEnumerator = _dictionary . _eventProperties ? . GetEnumerator ( ) ?? default ( Dictionary < object , PropertyValue > . Enumerator ) ;
700629}
701630}
702631