Exemple #1
0
        /// <summary>
        /// Updates an item if it exists in the dictionary
        /// </summary>
        /// <param name="target">The target concurrent dictionary</param>
        /// <param name="key">The key of the item to the update</param>
        /// <param name="update">A callback that performs the update</param>
        /// <param name="newValue">Receives the new value if the dictionary was updated</param>
        /// <returns>True if the item was updated, False if it does not exist</returns>
        /// <remarks>Implements a loop around TryGetValue and TryUpdate</remarks>
        public static bool TryUpdate <TKey, TValue>(this ConcurrentDictionary <TKey, TValue> target, TKey key, Func <TKey, TValue, TValue> update,
#if !NETSTANDARD2_0 && !NET40
                                                    [MaybeNullWhen(false)]
#endif
                                                    out TValue newValue) where TKey : notnull
        {
            while (target.TryGetValue(key, out var OldValue))
            {
                var NewValue = update(key, OldValue);

                if (target.TryUpdate(key, NewValue, OldValue))
                {
                    newValue = NewValue;

                    return(true);
                }
            }

            newValue = default !;
        //****************************************

        /// <summary>
        /// Adds or replaces a key/value pair
        /// </summary>
        /// <param name="key">The key to add or replace</param>
        /// <param name="value">The value to associate with the key</param>
        public void AddOrReplace(TKey key, TValue value)
        {               //****************************************
            GCReference NewHandle;

            //****************************************

            if (value == null)
            {
                throw new InvalidOperationException("Cannot add null to a Weak Dictionary");
            }

            for (; ;)
            {
                // Is this key already in the dictionary?
                if (_Dictionary.TryGetValue(key, out var MyHandle))
                {
                    try
                    {
                        var OldValue = (TValue?)MyHandle.Target;

                        // Yes. If the reference is the same, no need to change anything
                        if (object.ReferenceEquals(OldValue, value))
                        {
                            return;
                        }
                    }
                    catch (InvalidOperationException)
                    {
                        // The GCHandle was disposed, try again
                        continue;
                    }

                    // Reference has changed, create a new GCReference
                    NewHandle = new GCReference(value, _HandleType);

                    // Try and update the dictionary with the replacement value
                    if (_Dictionary.TryUpdate(key, NewHandle, MyHandle))
                    {
                        // Success, now we can safely expire the old handle
                        MyHandle.Dispose();

                        return;
                    }

                    // Key was updated elsewhere, ditch the updated value and try again
                    NewHandle.Dispose();

                    continue;
                }

                // Create a GC Handle to reference the object
                NewHandle = new GCReference(value, _HandleType);

                // Try and add it to the dictionary
                if (_Dictionary.TryAdd(key, NewHandle))
                {
                    return;                     // Success, return the result
                }
                // Key was added concurrently, free the handle we no longer need
                NewHandle.Dispose();

                // Loop back and try again
            }
        }