File: System\Windows\Forms\NonNullCollection.cs
Web Access
Project: src\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.
 
using System.Collections;
 
namespace System.Windows.Forms;
 
/// <summary>
///  Collection that protects against inserting null objects.
/// </summary>
[DebuggerDisplay("{DebuggerDisplay,nq}")]
internal abstract class NonNullCollection<T>
    : IList<T>, ICollection<T>, IEnumerable<T>, IEnumerable, IList, ICollection, IReadOnlyList<T>, IReadOnlyCollection<T>
    where T : class
{
    private readonly List<T> _list = [];
 
    public NonNullCollection() { }
 
    public NonNullCollection(IEnumerable<T> items) => AddRange(items);
 
    public T this[int index]
    {
        get => _list[index];
        set
        {
            _list[index] = value ?? ThrowArgumentNull(nameof(value));
            ItemAdded(value);
        }
    }
 
    public int Count => _list.Count;
 
    public bool IsReadOnly => ((ICollection<T>)_list).IsReadOnly;
 
    public void Add(T item)
    {
        _list.Add(item ?? ThrowArgumentNull(nameof(item)));
        ItemAdded(item);
    }
 
    public void Clear() => _list.Clear();
 
    public bool Contains(T item) => _list.Contains(item);
 
    public void CopyTo(T[] array, int arrayIndex) => _list.CopyTo(array, arrayIndex);
 
    public IEnumerator<T> GetEnumerator() => _list.GetEnumerator();
 
    public int IndexOf(T item) => _list.IndexOf(item);
 
    public void Insert(int index, T item)
    {
        _list.Insert(index, item ?? ThrowArgumentNull(nameof(item)));
        ItemAdded(item);
    }
 
    public bool Remove(T item) => _list.Remove(item);
 
    public void RemoveAt(int index) => _list.RemoveAt(index);
 
    IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable)_list).GetEnumerator();
 
    /// <summary>
    ///  Adds the items in <paramref name="items"/> to the collection.
    /// </summary>
    public void AddRange(IEnumerable<T> items)
    {
        // We don't want to put in partial items, so we need to enumerate twice to throw appropriately.
#pragma warning disable CA1851 // Possible multiple enumerations of 'IEnumerable' collection
        if (items is null || items.Contains(default))
        {
            ThrowArgumentNull(nameof(items));
        }
 
        _list.AddRange(items);
 
        foreach (T item in items)
        {
            ItemAdded(item);
        }
#pragma warning restore CA1851
    }
 
    int IList.Add(object? value)
    {
        int index = ((IList)_list).Add(value ?? ThrowArgumentNull(nameof(value)));
        ItemAdded((T)value);
        return index;
    }
 
    bool IList.Contains(object? value) => ((IList)_list).Contains(value);
 
    int IList.IndexOf(object? value) => ((IList)_list).IndexOf(value);
 
    void IList.Insert(int index, object? value)
    {
        ((IList)_list).Insert(index, value ?? ThrowArgumentNull(nameof(value)));
        ItemAdded((T)value);
    }
 
    void IList.Remove(object? value) => ((IList)_list).Remove(value);
 
    object? IList.this[int index]
    {
        get => ((IList)_list)[index];
        set
        {
            ((IList)_list)[index] = value ?? ThrowArgumentNull(nameof(value));
            ItemAdded((T)value);
        }
    }
 
    void ICollection.CopyTo(Array array, int index) => ((IList)_list).CopyTo(array, index);
 
    private string DebuggerDisplay => $"Count: {Count}";
 
    bool IList.IsFixedSize => ((IList)_list).IsFixedSize;
 
    object ICollection.SyncRoot => ((ICollection)_list).SyncRoot;
 
    bool ICollection.IsSynchronized => ((ICollection)_list).IsSynchronized;
 
    /// <summary>
    ///  Called for each item added to the collection.
    /// </summary>
    protected virtual void ItemAdded(T item)
    {
    }
 
    [DoesNotReturn]
    private static T ThrowArgumentNull(string name) => throw new ArgumentNullException(name);
}