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 ReadOnlyCollection
<T
> : IList
<T
>, IList
, IReadOnlyList
<T
>
16 private readonly IList
<T
> list
; // Do not rename (binary serialization)
18 public ReadOnlyCollection(IList
<T
> list
)
22 ThrowHelper
.ThrowArgumentNullException(ExceptionArgument
.list
);
27 public int Count
=> list
.Count
;
29 public T
this[int index
]
31 get { return list[index]; }
34 public bool Contains(T
value)
36 return list
.Contains(value);
39 public void CopyTo(T
[] array
, int index
)
41 list
.CopyTo(array
, index
);
44 public IEnumerator
<T
> GetEnumerator()
46 return list
.GetEnumerator();
49 public int IndexOf(T
value)
51 return list
.IndexOf(value);
54 protected IList
<T
> Items
=> list
;
56 bool ICollection
<T
>.IsReadOnly
=> true;
58 T IList
<T
>.this[int index
]
60 get { return list[index]; }
63 ThrowHelper
.ThrowNotSupportedException(ExceptionResource
.NotSupported_ReadOnlyCollection
);
67 void ICollection
<T
>.Add(T
value)
69 ThrowHelper
.ThrowNotSupportedException(ExceptionResource
.NotSupported_ReadOnlyCollection
);
72 void ICollection
<T
>.Clear()
74 ThrowHelper
.ThrowNotSupportedException(ExceptionResource
.NotSupported_ReadOnlyCollection
);
77 void IList
<T
>.Insert(int index
, T
value)
79 ThrowHelper
.ThrowNotSupportedException(ExceptionResource
.NotSupported_ReadOnlyCollection
);
82 bool ICollection
<T
>.Remove(T
value)
84 ThrowHelper
.ThrowNotSupportedException(ExceptionResource
.NotSupported_ReadOnlyCollection
);
88 void IList
<T
>.RemoveAt(int index
)
90 ThrowHelper
.ThrowNotSupportedException(ExceptionResource
.NotSupported_ReadOnlyCollection
);
93 IEnumerator IEnumerable
.GetEnumerator()
95 return ((IEnumerable
)list
).GetEnumerator();
98 bool ICollection
.IsSynchronized
=> false;
100 object ICollection
.SyncRoot
=> list
is ICollection coll
? coll
.SyncRoot
: this;
102 void ICollection
.CopyTo(Array array
, int index
)
106 ThrowHelper
.ThrowArgumentNullException(ExceptionArgument
.array
);
111 ThrowHelper
.ThrowArgumentException(ExceptionResource
.Arg_RankMultiDimNotSupported
);
114 if (array
.GetLowerBound(0) != 0)
116 ThrowHelper
.ThrowArgumentException(ExceptionResource
.Arg_NonZeroLowerBound
);
121 ThrowHelper
.ThrowIndexArgumentOutOfRange_NeedNonNegNumException();
124 if (array
.Length
- index
< Count
)
126 ThrowHelper
.ThrowArgumentException(ExceptionResource
.Arg_ArrayPlusOffTooSmall
);
129 if (array
is T
[] items
)
131 list
.CopyTo(items
, index
);
136 // Catch the obvious case assignment will fail.
137 // We can't find all possible problems by doing the check though.
138 // For example, if the element type of the Array is derived from T,
139 // we can't figure out if we can successfully copy the element beforehand.
141 Type targetType
= array
.GetType().GetElementType()!;
142 Type sourceType
= typeof(T
);
143 if (!(targetType
.IsAssignableFrom(sourceType
) || sourceType
.IsAssignableFrom(targetType
)))
145 ThrowHelper
.ThrowArgumentException_Argument_InvalidArrayType();
149 // We can't cast array of value type to object[], so we don't support
150 // widening of primitive types here.
152 object?[]? objects
= array
as object[];
155 ThrowHelper
.ThrowArgumentException_Argument_InvalidArrayType();
158 int count
= list
.Count
;
161 for (int i
= 0; i
< count
; i
++)
163 objects
[index
++] = list
[i
];
166 catch (ArrayTypeMismatchException
)
168 ThrowHelper
.ThrowArgumentException_Argument_InvalidArrayType();
173 bool IList
.IsFixedSize
=> true;
175 bool IList
.IsReadOnly
=> true;
177 object? IList
.this[int index
]
179 get { return list[index]; }
182 ThrowHelper
.ThrowNotSupportedException(ExceptionResource
.NotSupported_ReadOnlyCollection
);
186 int IList
.Add(object? value)
188 ThrowHelper
.ThrowNotSupportedException(ExceptionResource
.NotSupported_ReadOnlyCollection
);
194 ThrowHelper
.ThrowNotSupportedException(ExceptionResource
.NotSupported_ReadOnlyCollection
);
197 private static bool IsCompatibleObject(object? value)
199 // Non-null values are fine. Only accept nulls if T is a class or Nullable<U>.
200 // Note that default(T) is not equal to null for value types except when T is Nullable<U>.
201 return ((value is T
) || (value == null && default(T
)! == null));
204 bool IList
.Contains(object? value)
206 if (IsCompatibleObject(value))
208 return Contains((T
)value!);
213 int IList
.IndexOf(object? value)
215 if (IsCompatibleObject(value))
217 return IndexOf((T
)value!);
222 void IList
.Insert(int index
, object? value)
224 ThrowHelper
.ThrowNotSupportedException(ExceptionResource
.NotSupported_ReadOnlyCollection
);
227 void IList
.Remove(object? value)
229 ThrowHelper
.ThrowNotSupportedException(ExceptionResource
.NotSupported_ReadOnlyCollection
);
232 void IList
.RemoveAt(int index
)
234 ThrowHelper
.ThrowNotSupportedException(ExceptionResource
.NotSupported_ReadOnlyCollection
);