44using System ;
55using System . Collections ;
66using System . Collections . Generic ;
7+ using System . Diagnostics ;
78using System . Diagnostics . CodeAnalysis ;
89using System . Globalization ;
910using System . Linq ;
11+ using Microsoft . Shared . Diagnostics ;
12+
13+ #pragma warning disable S1144 // Unused private types or members should be removed
14+ #pragma warning disable S2365 // Properties should not make collection or array copies
15+ #pragma warning disable S3604 // Member initializer values should not be redundant
1016
1117namespace Microsoft . Extensions . AI ;
1218
1319/// <summary>Provides a dictionary used as the AdditionalProperties dictionary on Microsoft.Extensions.AI objects.</summary>
20+ [ DebuggerTypeProxy ( typeof ( DebugView ) ) ]
21+ [ DebuggerDisplay ( "Count = {Count}" ) ]
1422public sealed class AdditionalPropertiesDictionary : IDictionary < string , object ? > , IReadOnlyDictionary < string , object ? >
1523{
1624 /// <summary>The underlying dictionary.</summary>
@@ -77,6 +85,25 @@ public object? this[string key]
7785 /// <inheritdoc />
7886 public void Add ( string key , object ? value ) => _dictionary . Add ( key , value ) ;
7987
88+ /// <summary>Attempts to add the specified key and value to the dictionary.</summary>
89+ /// <param name="key">The key of the element to add.</param>
90+ /// <param name="value">The value of the element to add.</param>
91+ /// <returns><see langword="true"/> if the key/value pair was added to the dictionary successfully; otherwise, <see langword="false"/>.</returns>
92+ public bool TryAdd ( string key , object ? value )
93+ {
94+ #if NET
95+ return _dictionary . TryAdd ( key , value ) ;
96+ #else
97+ if ( ! _dictionary . ContainsKey ( key ) )
98+ {
99+ _dictionary . Add ( key , value ) ;
100+ return true ;
101+ }
102+
103+ return false ;
104+ #endif
105+ }
106+
80107 /// <inheritdoc />
81108 void ICollection < KeyValuePair < string , object ? > > . Add ( KeyValuePair < string , object ? > item ) => ( ( ICollection < KeyValuePair < string , object ? > > ) _dictionary ) . Add ( item ) ;
82109
@@ -93,11 +120,17 @@ public object? this[string key]
93120 void ICollection < KeyValuePair < string , object ? > > . CopyTo ( KeyValuePair < string , object ? > [ ] array , int arrayIndex ) =>
94121 ( ( ICollection < KeyValuePair < string , object ? > > ) _dictionary ) . CopyTo ( array , arrayIndex ) ;
95122
123+ /// <summary>
124+ /// Returns an enumerator that iterates through the <see cref="AdditionalPropertiesDictionary"/>.
125+ /// </summary>
126+ /// <returns>An <see cref="AdditionalPropertiesDictionary.Enumerator"/> that enumerates the contents of the <see cref="AdditionalPropertiesDictionary"/>.</returns>
127+ public Enumerator GetEnumerator ( ) => new ( _dictionary . GetEnumerator ( ) ) ;
128+
96129 /// <inheritdoc />
97- public IEnumerator < KeyValuePair < string , object ? > > GetEnumerator ( ) => _dictionary . GetEnumerator ( ) ;
130+ IEnumerator < KeyValuePair < string , object ? > > IEnumerable < KeyValuePair < string , object ? > > . GetEnumerator ( ) => GetEnumerator ( ) ;
98131
99132 /// <inheritdoc />
100- IEnumerator IEnumerable . GetEnumerator ( ) => _dictionary . GetEnumerator ( ) ;
133+ IEnumerator IEnumerable . GetEnumerator ( ) => GetEnumerator ( ) ;
101134
102135 /// <inheritdoc />
103136 public bool Remove ( string key ) => _dictionary . Remove ( key ) ;
@@ -156,4 +189,59 @@ public bool TryGetValue<T>(string key, [NotNullWhen(true)] out T? value)
156189 value = default ;
157190 return false ;
158191 }
192+
193+ /// <summary>Enumerates the elements of an <see cref="AdditionalPropertiesDictionary"/>.</summary>
194+ public struct Enumerator : IEnumerator < KeyValuePair < string , object ? > >
195+ {
196+ /// <summary>The wrapped dictionary enumerator.</summary>
197+ private Dictionary < string , object ? > . Enumerator _dictionaryEnumerator ;
198+
199+ /// <summary>Initializes a new instance of the <see cref="Enumerator"/> struct with the dictionary enumerator to wrap.</summary>
200+ /// <param name="dictionaryEnumerator">The dictionary enumerator to wrap.</param>
201+ internal Enumerator ( Dictionary < string , object ? > . Enumerator dictionaryEnumerator )
202+ {
203+ _dictionaryEnumerator = dictionaryEnumerator ;
204+ }
205+
206+ /// <inheritdoc />
207+ public KeyValuePair < string , object ? > Current => _dictionaryEnumerator . Current ;
208+
209+ /// <inheritdoc />
210+ object IEnumerator . Current => Current ;
211+
212+ /// <inheritdoc />
213+ public void Dispose ( ) => _dictionaryEnumerator . Dispose ( ) ;
214+
215+ /// <inheritdoc />
216+ public bool MoveNext ( ) => _dictionaryEnumerator . MoveNext ( ) ;
217+
218+ /// <inheritdoc />
219+ public void Reset ( ) => Reset ( ref _dictionaryEnumerator ) ;
220+
221+ /// <summary>Calls <see cref="IEnumerator.Reset"/> on an enumerator.</summary>
222+ private static void Reset < TEnumerator > ( ref TEnumerator enumerator )
223+ where TEnumerator : struct , IEnumerator
224+ {
225+ enumerator . Reset ( ) ;
226+ }
227+ }
228+
229+ /// <summary>Provides a debugger view for the collection.</summary>
230+ private sealed class DebugView ( AdditionalPropertiesDictionary properties )
231+ {
232+ private readonly AdditionalPropertiesDictionary _properties = Throw . IfNull ( properties ) ;
233+
234+ [ DebuggerBrowsable ( DebuggerBrowsableState . RootHidden ) ]
235+ public AdditionalProperty [ ] Items => ( from p in _properties select new AdditionalProperty ( p . Key , p . Value ) ) . ToArray ( ) ;
236+
237+ [ DebuggerDisplay ( "{Value}" , Name = "[{Key}]" ) ]
238+ public readonly struct AdditionalProperty ( string key , object ? value )
239+ {
240+ [ DebuggerBrowsable ( DebuggerBrowsableState . Collapsed ) ]
241+ public string Key { get ; } = key ;
242+
243+ [ DebuggerBrowsable ( DebuggerBrowsableState . Collapsed ) ]
244+ public object ? Value { get ; } = value ;
245+ }
246+ }
159247}
0 commit comments