| File: Collections\ReadOnlyCollection.cs | Web Access |
| Project: src\msbuild\src\Framework\Microsoft.Build.Framework.csproj (Microsoft.Build.Framework) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Collections; using System.Collections.Generic; using System.Linq; #nullable disable namespace Microsoft.Build.Collections { /// <summary> /// A read-only live wrapper over a collection. /// It does not prevent modification of the values themselves. /// </summary> /// <remarks> /// There is a type with the same name in the BCL, but it is actually a ReadOnlyList and does not accept an ICollection>T<. /// Thus this is an omission from the BCL. /// </remarks> /// <typeparam name="T">Type of element in the collection</typeparam> internal sealed class ReadOnlyCollection<T> : ICollection<T>, ICollection { /// <summary> /// Backing live enumerable. /// May be a collection. /// </summary> private IEnumerable<T> _backing; /// <summary> /// Construct a read only wrapper around the current contents /// of the IEnumerable, or around the backing collection if the /// IEnumerable is in fact a collection. /// </summary> internal ReadOnlyCollection(IEnumerable<T> backing) { Assumed.NotNull(backing, "Need backing collection"); _backing = backing; } /// <summary> /// Return the number of items in the backing collection /// </summary> public int Count { get { return BackingCollection.Count; } } /// <summary> /// Returns true. /// </summary> public bool IsReadOnly { get { return true; } } /// <summary> /// Whether collection is synchronized /// </summary> bool ICollection.IsSynchronized { get { return false; } } /// <summary> /// Sync root /// </summary> object ICollection.SyncRoot { get { return this; } } /// <summary> /// Get a backing ICollection. /// </summary> private ICollection<T> BackingCollection { get { ICollection<T> backingCollection = _backing as ICollection<T>; if (backingCollection == null) { backingCollection = new List<T>(_backing); _backing = backingCollection; } return backingCollection; } } /// <summary> /// Prohibited on read only collection: throws /// </summary> public void Add(T item) { throw new InvalidOperationException(SR.CollectionIsReadOnly); } /// <summary> /// Prohibited on read only collection: throws /// </summary> public void Clear() { throw new InvalidOperationException(SR.CollectionIsReadOnly); } /// <summary> /// Pass through for underlying collection /// </summary> public bool Contains(T item) { // UNDONE: IEnumerable.Contains<T>() does the ICollection check, // so we could just use IEnumerable.Contains<T>() here. if (!(_backing is ICollection<T>)) { return _backing.Contains<T>(item); } return BackingCollection.Contains(item); } /// <summary> /// Pass through for underlying collection /// </summary> public void CopyTo(T[] array, int arrayIndex) { ArgumentNullException.ThrowIfNull(array); ICollection<T> backingCollection = _backing as ICollection<T>; if (backingCollection != null) { backingCollection.CopyTo(array, arrayIndex); } else { int i = arrayIndex; foreach (T entry in _backing) { array[i] = entry; i++; } } } /// <summary> /// Prohibited on read only collection: throws /// </summary> public bool Remove(T item) { throw new InvalidOperationException(SR.CollectionIsReadOnly); } /// <summary> /// Pass through for underlying collection /// </summary> /// <comment> /// NOTE: This does NOT cause a copy into a List, since the /// backing enumerable suffices. /// </comment> public IEnumerator<T> GetEnumerator() { return _backing.GetEnumerator(); } /// <summary> /// Pass through for underlying collection /// </summary> /// <comment> /// NOTE: This does NOT cause a copy into a List, since the /// backing enumerable suffices. /// </comment> IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)_backing).GetEnumerator(); } /// <summary> /// ICollection version of CopyTo /// </summary> void ICollection.CopyTo(Array array, int index) { ArgumentNullException.ThrowIfNull(array); int i = index; foreach (T entry in _backing) { array.SetValue(entry, i); i++; } } } }