1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
5 using System
.Collections
.Generic
;
6 using System
.Diagnostics
;
8 namespace System
.Collections
.ObjectModel
11 [DebuggerTypeProxy(typeof(ICollectionDebugView
<>))]
12 [DebuggerDisplay("Count = {Count}")]
13 [System
.Runtime
.CompilerServices
.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
14 public class Collection
<T
> : IList
<T
>, IList
, IReadOnlyList
<T
>
16 private readonly IList
<T
> items
; // Do not rename (binary serialization)
20 items
= new List
<T
>();
23 public Collection(IList
<T
> list
)
27 ThrowHelper
.ThrowArgumentNullException(ExceptionArgument
.list
);
32 public int Count
=> items
.Count
;
34 protected IList
<T
> Items
=> items
;
36 public T
this[int index
]
38 get { return items[index]; }
43 ThrowHelper
.ThrowNotSupportedException(ExceptionResource
.NotSupported_ReadOnlyCollection
);
46 if ((uint)index
>= (uint)items
.Count
)
48 ThrowHelper
.ThrowArgumentOutOfRange_IndexException();
51 SetItem(index
, value);
55 public void Add(T item
)
59 ThrowHelper
.ThrowNotSupportedException(ExceptionResource
.NotSupported_ReadOnlyCollection
);
62 int index
= items
.Count
;
63 InsertItem(index
, item
);
70 ThrowHelper
.ThrowNotSupportedException(ExceptionResource
.NotSupported_ReadOnlyCollection
);
76 public void CopyTo(T
[] array
, int index
)
78 items
.CopyTo(array
, index
);
81 public bool Contains(T item
)
83 return items
.Contains(item
);
86 public IEnumerator
<T
> GetEnumerator()
88 return items
.GetEnumerator();
91 public int IndexOf(T item
)
93 return items
.IndexOf(item
);
96 public void Insert(int index
, T item
)
100 ThrowHelper
.ThrowNotSupportedException(ExceptionResource
.NotSupported_ReadOnlyCollection
);
103 if ((uint)index
> (uint)items
.Count
)
105 ThrowHelper
.ThrowArgumentOutOfRange_IndexException();
108 InsertItem(index
, item
);
111 public bool Remove(T item
)
113 if (items
.IsReadOnly
)
115 ThrowHelper
.ThrowNotSupportedException(ExceptionResource
.NotSupported_ReadOnlyCollection
);
118 int index
= items
.IndexOf(item
);
119 if (index
< 0) return false;
124 public void RemoveAt(int index
)
126 if (items
.IsReadOnly
)
128 ThrowHelper
.ThrowNotSupportedException(ExceptionResource
.NotSupported_ReadOnlyCollection
);
131 if ((uint)index
>= (uint)items
.Count
)
133 ThrowHelper
.ThrowArgumentOutOfRange_IndexException();
139 protected virtual void ClearItems()
144 protected virtual void InsertItem(int index
, T item
)
146 items
.Insert(index
, item
);
149 protected virtual void RemoveItem(int index
)
151 items
.RemoveAt(index
);
154 protected virtual void SetItem(int index
, T item
)
159 bool ICollection
<T
>.IsReadOnly
=> items
.IsReadOnly
;
161 IEnumerator IEnumerable
.GetEnumerator()
163 return ((IEnumerable
)items
).GetEnumerator();
166 bool ICollection
.IsSynchronized
=> false;
168 object ICollection
.SyncRoot
=> items
is ICollection coll
? coll
.SyncRoot
: this;
170 void ICollection
.CopyTo(Array array
, int index
)
174 ThrowHelper
.ThrowArgumentNullException(ExceptionArgument
.array
);
179 ThrowHelper
.ThrowArgumentException(ExceptionResource
.Arg_RankMultiDimNotSupported
);
182 if (array
.GetLowerBound(0) != 0)
184 ThrowHelper
.ThrowArgumentException(ExceptionResource
.Arg_NonZeroLowerBound
);
189 ThrowHelper
.ThrowIndexArgumentOutOfRange_NeedNonNegNumException();
192 if (array
.Length
- index
< Count
)
194 ThrowHelper
.ThrowArgumentException(ExceptionResource
.Arg_ArrayPlusOffTooSmall
);
197 if (array
is T
[] tArray
)
199 items
.CopyTo(tArray
, index
);
204 // Catch the obvious case assignment will fail.
205 // We can't find all possible problems by doing the check though.
206 // For example, if the element type of the Array is derived from T,
207 // we can't figure out if we can successfully copy the element beforehand.
209 Type targetType
= array
.GetType().GetElementType()!;
210 Type sourceType
= typeof(T
);
211 if (!(targetType
.IsAssignableFrom(sourceType
) || sourceType
.IsAssignableFrom(targetType
)))
213 ThrowHelper
.ThrowArgumentException_Argument_InvalidArrayType();
217 // We can't cast array of value type to object[], so we don't support
218 // widening of primitive types here.
220 object?[]? objects
= array
as object[];
223 ThrowHelper
.ThrowArgumentException_Argument_InvalidArrayType();
226 int count
= items
.Count
;
229 for (int i
= 0; i
< count
; i
++)
231 objects
[index
++] = items
[i
];
234 catch (ArrayTypeMismatchException
)
236 ThrowHelper
.ThrowArgumentException_Argument_InvalidArrayType();
241 object? IList
.this[int index
]
243 get { return items[index]; }
246 ThrowHelper
.IfNullAndNullsAreIllegalThenThrow
<T
>(value, ExceptionArgument
.value);
248 T item
= default(T
)!;
254 catch (InvalidCastException
)
256 ThrowHelper
.ThrowWrongValueTypeArgumentException(value, typeof(T
));
263 bool IList
.IsReadOnly
=> items
.IsReadOnly
;
265 bool IList
.IsFixedSize
269 // There is no IList<T>.IsFixedSize, so we must assume that only
270 // readonly collections are fixed size, if our internal item
271 // collection does not implement IList. Note that Array implements
272 // IList, and therefore T[] and U[] will be fixed-size.
273 if (items
is IList list
)
275 return list
.IsFixedSize
;
277 return items
.IsReadOnly
;
281 int IList
.Add(object? value)
283 if (items
.IsReadOnly
)
285 ThrowHelper
.ThrowNotSupportedException(ExceptionResource
.NotSupported_ReadOnlyCollection
);
287 ThrowHelper
.IfNullAndNullsAreIllegalThenThrow
<T
>(value, ExceptionArgument
.value);
289 T item
= default(T
)!;
295 catch (InvalidCastException
)
297 ThrowHelper
.ThrowWrongValueTypeArgumentException(value, typeof(T
));
302 return this.Count
- 1;
305 bool IList
.Contains(object? value)
307 if (IsCompatibleObject(value))
309 return Contains((T
)value!);
314 int IList
.IndexOf(object? value)
316 if (IsCompatibleObject(value))
318 return IndexOf((T
)value!);
323 void IList
.Insert(int index
, object? value)
325 if (items
.IsReadOnly
)
327 ThrowHelper
.ThrowNotSupportedException(ExceptionResource
.NotSupported_ReadOnlyCollection
);
329 ThrowHelper
.IfNullAndNullsAreIllegalThenThrow
<T
>(value, ExceptionArgument
.value);
331 T item
= default(T
)!;
337 catch (InvalidCastException
)
339 ThrowHelper
.ThrowWrongValueTypeArgumentException(value, typeof(T
));
345 void IList
.Remove(object? value)
347 if (items
.IsReadOnly
)
349 ThrowHelper
.ThrowNotSupportedException(ExceptionResource
.NotSupported_ReadOnlyCollection
);
352 if (IsCompatibleObject(value))
358 private static bool IsCompatibleObject(object? value)
360 // Non-null values are fine. Only accept nulls if T is a class or Nullable<U>.
361 // Note that default(T) is not equal to null for value types except when T is Nullable<U>.
362 return ((value is T
) || (value == null && default(T
)! == null));