| File: System\Collections\Generic\WeakRefCollection.cs | Web Access |
| Project: src\winforms\src\System.Windows.Forms.Primitives\src\System.Windows.Forms.Primitives.csproj (System.Windows.Forms.Primitives) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. namespace System.Collections.Generic; /// <summary> /// Weak reference collection of <typeparamref name="T"/>. /// </summary> internal sealed class WeakRefCollection<T>() : IEnumerable<T> where T : class { private readonly List<WeakReference<T>> _list = []; /// <summary> /// If set to true, triggers the execution of ScavengeReferences during the next /// <see cref="Add(T)"/> call to clean up dead weak references. /// </summary> private bool _scavenge; public T? this[int index] { get { _scavenge = !_list[index].TryGetTarget(out T? target); return target; } set { ArgumentNullException.ThrowIfNull(value, nameof(value)); _list[index] = new(value); } } /// <summary> /// Cleans up dead weak references. /// </summary> public void ScavengeReferences() { for (int i = Count - 1; i >= 0; i--) { if (!_list[i].TryGetTarget(out T? _)) { _list.RemoveAt(i); } } _scavenge = false; } public void RemoveAt(int index) => _list.RemoveAt(index); public void Remove(T value) { int index = IndexOf(value); if (index != -1) { _list.RemoveAt(index); } } public int IndexOf(T value) { for (int i = 0; i < _list.Count; i++) { if (!_list[i].TryGetTarget(out T? target)) { _scavenge = true; } else if (target == value) { return i; } } return -1; } public bool Contains(T value) => IndexOf(value) != -1; public void Add(T value) { if (_scavenge) { ScavengeReferences(); } _list.Add(new(value)); } public int Count => _list.Count; public IEnumerator<T> GetEnumerator() { foreach (WeakReference<T> weakRef in _list) { // Safely try to get the target. If it's still alive, yield return it. if (weakRef.TryGetTarget(out T? target)) { yield return target; } else { _scavenge = true; } } } IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); }