Пример #1
0
        void P_EH_Key_AfterDisposed(object sender, DisposeEventArgs eventArgs, P_ValueHolder valueHolder)
        {
            var key = sender.EnsureNotNull(nameof(sender)).EnsureOfType <TKey>().Value;

            eventArgs.EnsureNotNull(nameof(eventArgs));
            valueHolder.EnsureNotNull(nameof(valueHolder));
            //
            itrlck
            .Update(
                location: ref _innerTable,
                transform:
                (ImmutableDictionary <TKey, P_ValueHolder> locCurrent) => {
                var locChanged = locCurrent;
                if (ImmutableInterlocked.TryRemove(location: ref locChanged, key: key, value: out var locRemoving) && ReferenceEquals(valueHolder, locRemoving))
                {
                    return(locChanged);
                }
Пример #2
0
        TValue P_GetOrAdd(ArgumentUtilitiesHandle <TKey> key, Func <TKey, TValue> valueFactory, Action <TKey, TValue> valueCleanup, bool keyAbsenceRequired, out bool added, bool keyDisposeTolerant = default, TValue keyDisposeSentinel = default)
        {
            key.EnsureNotNull();
            if (valueFactory is null)
            {
                throw new ArgumentNullException(paramName: nameof(valueFactory));
            }
            //
            valueCleanup = valueCleanup ?? __NopValueCleanup;
            var           isAdded             = false;
            P_ValueHolder newValueHolder      = default;
            P_ValueHolder existingValueHolder = default;
            Exception     caughtException     = default;

            try {
                itrlck
                .Update(
                    location: ref _innerTable,
                    transform:
                    (ImmutableDictionary <TKey, P_ValueHolder> locCurrent) => {
                    ImmutableDictionary <TKey, P_ValueHolder> locChanged;
                    if (keyAbsenceRequired)
                    {
                        try {
                            locChanged = locCurrent.Add(key: key.Value, value: newValueHolder ?? (newValueHolder = new P_ValueHolder()));
                        }
                        catch (ArgumentException locException) {
                            throw
                            new ArgumentException(
                                paramName: key.Name,
                                message: $"Specified key is already exists in this table.{Environment.NewLine}\tKey:{key.Value.FmtStr().GNLI2()}",
                                innerException: locException);
                        }
                    }
                    else
                    {
                        locChanged         = locCurrent;
                        var locValueHolder = ImmutableInterlocked.GetOrAdd(location: ref locChanged, key: key.Value, valueFactory: locKey => newValueHolder ?? (newValueHolder = new P_ValueHolder()));
                        if (ReferenceEquals(locCurrent, locChanged))
                        {
                            // Словарь не был изменён (а значит, в словаре уже присутствовало значение для указанного ключа).
                            //
                            existingValueHolder = locValueHolder;
                        }
                    }
                    if (!ReferenceEquals(locCurrent, locChanged) && newValueHolder.ValueCleanup is null)
                    {
                        newValueHolder.Value        = valueFactory(arg: key.Value);
                        newValueHolder.ValueCleanup = valueCleanup;
                        if (keyDisposeTolerant)
                        {
                            if (key.Value.IsDisposeRequested)
                            {
                                return(locCurrent);
                            }
                            else
                            {
                                try {
                                    key.Value.AfterDisposed += (locSender, locEventArgs) => P_EH_Key_AfterDisposed(sender: locSender, eventArgs: locEventArgs, valueHolder: newValueHolder);
                                }
                                catch (ObjectDisposedException) {
                                    return(locCurrent);
                                }
                            }
                        }
                        else
                        {
                            key.Value.AfterDisposed += (locSender, locEventArgs) => P_EH_Key_AfterDisposed(sender: locSender, eventArgs: locEventArgs, valueHolder: newValueHolder);
                        }
                    }
                    return(locChanged);
                },
                    isUpdated: out isAdded);
                if (isAdded)
                {
                    added = true;
                    return(newValueHolder.Value);
                }
                else if (keyDisposeTolerant)
                {
                    added = false;
                    return(keyDisposeSentinel);
                }
                else
                {
                    added = false;
                    return(existingValueHolder.Value);
                }
            }
            catch (Exception exception) {
                caughtException = exception;
                throw;
            }
            finally {
                if (!(isAdded || newValueHolder is null))
                {
                    try {
                        itrlck.SetNull(location: ref newValueHolder.ValueCleanup)?.Invoke(arg1: key.Value, arg2: newValueHolder.Value);
                    }
                    catch (Exception exception) {
                        if (caughtException is null)
                        {
                            throw;
                        }
                        else
                        {
                            throw new AggregateException(caughtException, exception);
                        }
                    }
                }
            }
        }