@@ -184,6 +184,21 @@ private bool GetOrDiscard(I item, out V value)
184184 return true ;
185185 }
186186
187+ private bool TryAdd ( K key , V value )
188+ {
189+ var newItem = this . itemPolicy . CreateItem ( key , value ) ;
190+
191+ if ( this . dictionary . TryAdd ( key , newItem ) )
192+ {
193+ this . hotQueue . Enqueue ( newItem ) ;
194+ Cycle ( Interlocked . Increment ( ref counter . hot ) ) ;
195+ return true ;
196+ }
197+
198+ Disposer < V > . Dispose ( newItem . Value ) ;
199+ return false ;
200+ }
201+
187202 ///<inheritdoc/>
188203 public V GetOrAdd ( K key , Func < K , V > valueFactory )
189204 {
@@ -195,17 +210,41 @@ public V GetOrAdd(K key, Func<K, V> valueFactory)
195210 }
196211
197212 // The value factory may be called concurrently for the same key, but the first write to the dictionary wins.
198- // This is identical logic in ConcurrentDictionary.GetOrAdd method.
199- var newItem = this . itemPolicy . CreateItem ( key , valueFactory ( key ) ) ;
213+ value = valueFactory ( key ) ;
200214
201- if ( this . dictionary . TryAdd ( key , newItem ) )
215+ if ( TryAdd ( key , value ) )
202216 {
203- this . hotQueue . Enqueue ( newItem ) ;
204- Cycle ( Interlocked . Increment ( ref counter . hot ) ) ;
205- return newItem . Value ;
217+ return value ;
206218 }
219+ }
220+ }
207221
208- Disposer < V > . Dispose ( newItem . Value ) ;
222+ /// <summary>
223+ /// Adds a key/value pair to the cache if the key does not already exist. Returns the new value, or the
224+ /// existing value if the key already exists.
225+ /// </summary>
226+ /// <typeparam name="TArg">The type of an argument to pass into valueFactory.</typeparam>
227+ /// <param name="key">The key of the element to add.</param>
228+ /// <param name="valueFactory">The factory function used to generate a value for the key.</param>
229+ /// <param name="factoryArgument">An argument value to pass into valueFactory.</param>
230+ /// <returns>The value for the key. This will be either the existing value for the key if the key is already
231+ /// in the cache, or the new value if the key was not in the cache.</returns>
232+ public V GetOrAdd < TArg > ( K key , Func < K , TArg , V > valueFactory , TArg factoryArgument )
233+ {
234+ while ( true )
235+ {
236+ if ( this . TryGet ( key , out var value ) )
237+ {
238+ return value ;
239+ }
240+
241+ // The value factory may be called concurrently for the same key, but the first write to the dictionary wins.
242+ value = valueFactory ( key , factoryArgument ) ;
243+
244+ if ( TryAdd ( key , value ) )
245+ {
246+ return value ;
247+ }
209248 }
210249 }
211250
@@ -221,16 +260,40 @@ public async ValueTask<V> GetOrAddAsync(K key, Func<K, Task<V>> valueFactory)
221260
222261 // The value factory may be called concurrently for the same key, but the first write to the dictionary wins.
223262 // This is identical logic in ConcurrentDictionary.GetOrAdd method.
224- var newItem = this . itemPolicy . CreateItem ( key , await valueFactory ( key ) . ConfigureAwait ( false ) ) ;
263+ value = await valueFactory ( key ) . ConfigureAwait ( false ) ;
225264
226- if ( this . dictionary . TryAdd ( key , newItem ) )
265+ if ( TryAdd ( key , value ) )
227266 {
228- this . hotQueue . Enqueue ( newItem ) ;
229- Cycle ( Interlocked . Increment ( ref counter . hot ) ) ;
230- return newItem . Value ;
267+ return value ;
231268 }
269+ }
270+ }
232271
233- Disposer < V > . Dispose ( newItem . Value ) ;
272+ /// <summary>
273+ /// Adds a key/value pair to the cache if the key does not already exist. Returns the new value, or the
274+ /// existing value if the key already exists.
275+ /// </summary>
276+ /// <typeparam name="TArg">The type of an argument to pass into valueFactory.</typeparam>
277+ /// <param name="key">The key of the element to add.</param>
278+ /// <param name="valueFactory">The factory function used to asynchronously generate a value for the key.</param>
279+ /// <param name="factoryArgument">An argument value to pass into valueFactory.</param>
280+ /// <returns>A task that represents the asynchronous GetOrAdd operation.</returns>
281+ public async ValueTask < V > GetOrAddAsync < TArg > ( K key , Func < K , TArg , Task < V > > valueFactory , TArg factoryArgument )
282+ {
283+ while ( true )
284+ {
285+ if ( this . TryGet ( key , out var value ) )
286+ {
287+ return value ;
288+ }
289+
290+ // The value factory may be called concurrently for the same key, but the first write to the dictionary wins.
291+ value = await valueFactory ( key , factoryArgument ) . ConfigureAwait ( false ) ;
292+
293+ if ( TryAdd ( key , value ) )
294+ {
295+ return value ;
296+ }
234297 }
235298 }
236299
0 commit comments