@@ -192,7 +192,7 @@ public KVObject this[string key]
192192 set
193193 {
194194 ArgumentNullException . ThrowIfNull ( key ) ;
195- SetChild ( key , value ) ;
195+ TryInsert ( key , value ?? Null ( ) , InsertionBehavior . OverwriteExisting ) ;
196196 }
197197 }
198198
@@ -296,22 +296,25 @@ public bool ContainsKey(string name)
296296
297297 /// <summary>
298298 /// Adds a named child to this collection.
299+ /// For dictionary-backed collections, throws if the key already exists.
300+ /// For list-backed collections, always appends (duplicate keys are allowed).
299301 /// </summary>
302+ /// <exception cref="ArgumentException">The key already exists in a dictionary-backed collection.</exception>
300303 public void Add ( string key , KVObject value )
301304 {
302305 ArgumentNullException . ThrowIfNull ( key ) ;
306+ TryInsert ( key , value , InsertionBehavior . ThrowOnExisting ) ;
307+ }
303308
304- switch ( _ref )
305- {
306- case Dictionary < string , KVObject > dict :
307- dict [ key ] = value ;
308- break ;
309- case List < KeyValuePair < string , KVObject > > list when ValueType == KVValueType . Collection :
310- list . Add ( new KeyValuePair < string , KVObject > ( key , value ) ) ;
311- break ;
312- default :
313- throw new InvalidOperationException ( $ "Cannot add a named child to a { ValueType } value.") ;
314- }
309+ /// <summary>
310+ /// Tries to add a named child to this collection.
311+ /// Returns <c>false</c> if the key already exists in a dictionary-backed collection.
312+ /// For list-backed collections, always succeeds (duplicate keys are allowed).
313+ /// </summary>
314+ public bool TryAdd ( string key , KVObject value )
315+ {
316+ ArgumentNullException . ThrowIfNull ( key ) ;
317+ return TryInsert ( key , value , InsertionBehavior . None ) ;
315318 }
316319
317320 /// <summary>
@@ -500,48 +503,66 @@ public ReadOnlySpan<byte> AsSpan()
500503 internal List < KVObject > GetArrayList ( )
501504 => ( List < KVObject > ) _ref ;
502505
503- internal Dictionary < string , KVObject > GetCollectionDict ( )
504- => ( Dictionary < string , KVObject > ) _ref ;
505-
506- internal List < KeyValuePair < string , KVObject > > GetCollectionList ( )
507- => ( List < KeyValuePair < string , KVObject > > ) _ref ;
508-
509506 #endregion
510507
511508 #region Private helpers
512509
513- private void SetChild ( string key , KVObject value )
510+ private enum InsertionBehavior
514511 {
515- value ??= Null ( ) ;
512+ None ,
513+ OverwriteExisting ,
514+ ThrowOnExisting ,
515+ }
516516
517+ private bool TryInsert ( string key , KVObject value , InsertionBehavior behavior )
518+ {
517519 switch ( _ref )
518520 {
519521 case Dictionary < string , KVObject > dict :
520- dict [ key ] = value ;
521- break ;
522- case List < KeyValuePair < string , KVObject > > list when ValueType == KVValueType . Collection :
523- var firstIndex = list . FindIndex ( c => c . Key == key ) ;
524- if ( firstIndex >= 0 )
522+ if ( behavior == InsertionBehavior . OverwriteExisting )
525523 {
526- list [ firstIndex ] = new KeyValuePair < string , KVObject > ( key , value ) ;
524+ dict [ key ] = value ;
525+ return true ;
526+ }
527+
528+ if ( dict . TryAdd ( key , value ) )
529+ {
530+ return true ;
531+ }
532+
533+ if ( behavior == InsertionBehavior . ThrowOnExisting )
534+ {
535+ throw new ArgumentException ( $ "An item with the same key has already been added. Key: { key } ") ;
536+ }
527537
528- // Remove any remaining duplicates after the replaced entry
529- for ( var i = list . Count - 1 ; i > firstIndex ; i -- )
538+ return false ;
539+
540+ case List < KeyValuePair < string , KVObject > > list when ValueType == KVValueType . Collection :
541+ if ( behavior == InsertionBehavior . OverwriteExisting )
542+ {
543+ var firstIndex = list . FindIndex ( c => c . Key == key ) ;
544+ if ( firstIndex >= 0 )
530545 {
531- if ( list [ i ] . Key == key )
546+ list [ firstIndex ] = new KeyValuePair < string , KVObject > ( key , value ) ;
547+
548+ // Remove any remaining duplicates after the replaced entry
549+ for ( var i = list . Count - 1 ; i > firstIndex ; i -- )
532550 {
533- list . RemoveAt ( i ) ;
551+ if ( list [ i ] . Key == key )
552+ {
553+ list . RemoveAt ( i ) ;
554+ }
534555 }
556+
557+ return true ;
535558 }
536559 }
537- else
538- {
539- list . Add ( new KeyValuePair < string , KVObject > ( key , value ) ) ;
540- }
541560
542- break ;
561+ list . Add ( new KeyValuePair < string , KVObject > ( key , value ) ) ;
562+ return true ;
563+
543564 default :
544- throw new InvalidOperationException ( $ "Cannot set a child on a { ValueType } value.") ;
565+ throw new InvalidOperationException ( $ "Cannot insert a named child into a { ValueType } value.") ;
545566 }
546567 }
547568
0 commit comments