| File: System\ComponentModel\CollectibleKeyConcurrentHashtable.cs | Web Access |
| Project: src\runtime\src\libraries\System.ComponentModel.TypeConverter\src\System.ComponentModel.TypeConverter.csproj (System.ComponentModel.TypeConverter) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Reflection; using System.Runtime.CompilerServices; namespace System.ComponentModel { /// <summary> /// Concurrent dictionary that maps MemberInfo object key to an object. /// Uses ConditionalWeakTable for the collectible keys (if MemberInfo.IsCollectible is true) and /// ConcurrentDictionary for non-collectible keys. /// </summary> internal sealed class CollectibleKeyConcurrentHashtable<TKey, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] TValue> : IEnumerable<KeyValuePair<TKey, TValue>> where TKey : MemberInfo where TValue : class? { private readonly ConcurrentDictionary<TKey, TValue> _defaultTable = new ConcurrentDictionary<TKey, TValue>(); private readonly ConditionalWeakTable<TKey, object?> _collectibleTable = new ConditionalWeakTable<TKey, object?>(); public TValue? this[TKey key] { get { return TryGetValue(key, out TValue? value) ? value : default; } set { if (!key.IsCollectible) { _defaultTable[key] = value!; } else { _collectibleTable.AddOrUpdate(key, value); } } } public bool ContainsKey(TKey key) { return !key.IsCollectible ? _defaultTable.ContainsKey(key) : _collectibleTable.TryGetValue(key, out _); } public bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value) { if (!key.IsCollectible) return _defaultTable.TryGetValue(key, out value); if (_collectibleTable.TryGetValue(key, out object? valueObj) && valueObj != null) { value = (TValue)valueObj; return true; } value = default; return false; } public bool TryAdd(TKey key, TValue value) { return !key.IsCollectible ? _defaultTable.TryAdd(key, value) : _collectibleTable.TryAdd(key, value); } public void Clear() { _defaultTable.Clear(); _collectibleTable.Clear(); } public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() => new Enumerator(_defaultTable.GetEnumerator(), ((IEnumerable<KeyValuePair<TKey, object?>>)_collectibleTable).GetEnumerator()); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); private sealed class Enumerator : IEnumerator<KeyValuePair<TKey, TValue>> { private readonly IEnumerator<KeyValuePair<TKey, TValue>> _defaultEnumerator; private readonly IEnumerator<KeyValuePair<TKey, object?>> _collectibleEnumerator; private bool _enumeratingCollectibleEnumerator; public Enumerator(IEnumerator<KeyValuePair<TKey, TValue>> defaultEnumerator, IEnumerator<KeyValuePair<TKey, object?>> collectibleEnumerator) { _defaultEnumerator = defaultEnumerator; _collectibleEnumerator = collectibleEnumerator; _enumeratingCollectibleEnumerator = false; } public KeyValuePair<TKey, TValue> Current { get; private set; } object IEnumerator.Current => Current; public void Dispose() { _defaultEnumerator.Dispose(); _collectibleEnumerator.Dispose(); } public bool MoveNext() { if (!_enumeratingCollectibleEnumerator && _defaultEnumerator.MoveNext()) { Current = _defaultEnumerator.Current; return true; } _enumeratingCollectibleEnumerator = true; while (_collectibleEnumerator.MoveNext()) { if (_collectibleEnumerator.Current.Value is TValue value) { Current = new KeyValuePair<TKey, TValue>(_collectibleEnumerator.Current.Key, value); return true; } } Current = default; return false; } public void Reset() { _defaultEnumerator.Reset(); _collectibleEnumerator.Reset(); _enumeratingCollectibleEnumerator = false; Current = default; } } } }