1 // Copyright (c) Microsoft. All rights reserved. 2 // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 //----------------------------------------------------------------------- 4 // </copyright> 5 // <summary>A read-only wrapper around an ICollection<K></summary> 6 //----------------------------------------------------------------------- 7 8 using System; 9 using System.Collections.Generic; 10 using System.Linq; 11 using System.Text; 12 using System.Collections; 13 using Microsoft.Build.Shared; 14 15 namespace Microsoft.Build.Collections 16 { 17 /// <summary> 18 /// A read-only live wrapper over a collection. 19 /// It does not prevent modification of the values themselves. 20 /// </summary> 21 /// <remarks> 22 /// There is a type with the same name in the BCL, but it is actually a ReadOnlyList and does not accept an ICollection>T<. 23 /// Thus this is an omission from the BCL. 24 /// </remarks> 25 /// <typeparam name="T">Type of element in the collection</typeparam> 26 internal class ReadOnlyCollection<T> : ICollection<T>, ICollection 27 { 28 /// <summary> 29 /// Backing live enumerable. 30 /// May be a collection. 31 /// </summary> 32 private IEnumerable<T> _backing; 33 34 /// <summary> 35 /// Construct a read only wrapper around the current contents 36 /// of the IEnumerable, or around the backing collection if the 37 /// IEnumerable is in fact a collection. 38 /// </summary> ReadOnlyCollection(IEnumerable<T> backing)39 internal ReadOnlyCollection(IEnumerable<T> backing) 40 { 41 ErrorUtilities.VerifyThrow(backing != null, "Need backing collection"); 42 43 _backing = backing; 44 } 45 46 /// <summary> 47 /// Return the number of items in the backing collection 48 /// </summary> 49 public int Count 50 { 51 get 52 { 53 return BackingCollection.Count; 54 } 55 } 56 57 /// <summary> 58 /// Returns true. 59 /// </summary> 60 public bool IsReadOnly 61 { 62 get { return true; } 63 } 64 65 /// <summary> 66 /// Whether collection is synchronized 67 /// </summary> 68 bool ICollection.IsSynchronized 69 { 70 get { return false; } 71 } 72 73 /// <summary> 74 /// Sync root 75 /// </summary> 76 object ICollection.SyncRoot 77 { 78 get { return this; } 79 } 80 81 /// <summary> 82 /// Get a backing ICollection. 83 /// </summary> 84 private ICollection<T> BackingCollection 85 { 86 get 87 { 88 ICollection<T> backingCollection = _backing as ICollection<T>; 89 if (backingCollection == null) 90 { 91 backingCollection = new List<T>(_backing); 92 _backing = backingCollection; 93 } 94 95 return backingCollection; 96 } 97 } 98 99 /// <summary> 100 /// Prohibited on read only collection: throws 101 /// </summary> Add(T item)102 public void Add(T item) 103 { 104 ErrorUtilities.ThrowInvalidOperation("OM_NotSupportedReadOnlyCollection"); 105 } 106 107 /// <summary> 108 /// Prohibited on read only collection: throws 109 /// </summary> Clear()110 public void Clear() 111 { 112 ErrorUtilities.ThrowInvalidOperation("OM_NotSupportedReadOnlyCollection"); 113 } 114 115 /// <summary> 116 /// Pass through for underlying collection 117 /// </summary> Contains(T item)118 public bool Contains(T item) 119 { 120 // UNDONE: IEnumerable.Contains<T>() does the ICollection check, 121 // so we could just use IEnumerable.Contains<T>() here. 122 if (!(_backing is ICollection<T>)) 123 { 124 return _backing.Contains<T>(item); 125 } 126 127 return BackingCollection.Contains(item); 128 } 129 130 /// <summary> 131 /// Pass through for underlying collection 132 /// </summary> CopyTo(T[] array, int arrayIndex)133 public void CopyTo(T[] array, int arrayIndex) 134 { 135 ErrorUtilities.VerifyThrowArgumentNull(array, "array"); 136 137 ICollection<T> backingCollection = _backing as ICollection<T>; 138 if (backingCollection != null) 139 { 140 backingCollection.CopyTo(array, arrayIndex); 141 } 142 else 143 { 144 int i = arrayIndex; 145 foreach (T entry in _backing) 146 { 147 array[i] = entry; 148 i++; 149 } 150 } 151 } 152 153 /// <summary> 154 /// Prohibited on read only collection: throws 155 /// </summary> Remove(T item)156 public bool Remove(T item) 157 { 158 ErrorUtilities.ThrowInvalidOperation("OM_NotSupportedReadOnlyCollection"); 159 return false; 160 } 161 162 /// <summary> 163 /// Pass through for underlying collection 164 /// </summary> 165 /// <comment> 166 /// NOTE: This does NOT cause a copy into a List, since the 167 /// backing enumerable suffices. 168 /// </comment> GetEnumerator()169 public IEnumerator<T> GetEnumerator() 170 { 171 return _backing.GetEnumerator(); 172 } 173 174 /// <summary> 175 /// Pass through for underlying collection 176 /// </summary> 177 /// <comment> 178 /// NOTE: This does NOT cause a copy into a List, since the 179 /// backing enumerable suffices. 180 /// </comment> IEnumerable.GetEnumerator()181 IEnumerator IEnumerable.GetEnumerator() 182 { 183 return ((IEnumerable)_backing).GetEnumerator(); 184 } 185 186 /// <summary> 187 /// ICollection version of CopyTo 188 /// </summary> ICollection.CopyTo(Array array, int index)189 void ICollection.CopyTo(Array array, int index) 190 { 191 ErrorUtilities.VerifyThrowArgumentNull(array, "array"); 192 193 int i = index; 194 foreach (T entry in _backing) 195 { 196 array.SetValue(entry, i); 197 i++; 198 } 199 } 200 } 201 } 202