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); }
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); } } } } }