diff options
Diffstat (limited to 'src/mscorlib/shared/System/Collections/ObjectModel/Collection.cs')
-rw-r--r-- | src/mscorlib/shared/System/Collections/ObjectModel/Collection.cs | 396 |
1 files changed, 396 insertions, 0 deletions
diff --git a/src/mscorlib/shared/System/Collections/ObjectModel/Collection.cs b/src/mscorlib/shared/System/Collections/ObjectModel/Collection.cs new file mode 100644 index 0000000000..75e88eccb3 --- /dev/null +++ b/src/mscorlib/shared/System/Collections/ObjectModel/Collection.cs @@ -0,0 +1,396 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Diagnostics; + +namespace System.Collections.ObjectModel +{ + [Serializable] + [DebuggerTypeProxy(typeof(Mscorlib_CollectionDebugView<>))] + [DebuggerDisplay("Count = {Count}")] + [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] + public class Collection<T> : IList<T>, IList, IReadOnlyList<T> + { + private IList<T> items; // Do not rename (binary serialization) + [NonSerialized] + private Object _syncRoot; + + public Collection() + { + items = new List<T>(); + } + + public Collection(IList<T> list) + { + if (list == null) + { + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.list); + } + items = list; + } + + public int Count + { + get { return items.Count; } + } + + protected IList<T> Items + { + get { return items; } + } + + public T this[int index] + { + get { return items[index]; } + set + { + if (items.IsReadOnly) + { + ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection); + } + + if (index < 0 || index >= items.Count) + { + ThrowHelper.ThrowArgumentOutOfRange_IndexException(); + } + + SetItem(index, value); + } + } + + public void Add(T item) + { + if (items.IsReadOnly) + { + ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection); + } + + int index = items.Count; + InsertItem(index, item); + } + + public void Clear() + { + if (items.IsReadOnly) + { + ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection); + } + + ClearItems(); + } + + public void CopyTo(T[] array, int index) + { + items.CopyTo(array, index); + } + + public bool Contains(T item) + { + return items.Contains(item); + } + + public IEnumerator<T> GetEnumerator() + { + return items.GetEnumerator(); + } + + public int IndexOf(T item) + { + return items.IndexOf(item); + } + + public void Insert(int index, T item) + { + if (items.IsReadOnly) + { + ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection); + } + + if (index < 0 || index > items.Count) + { + ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index, ExceptionResource.ArgumentOutOfRange_ListInsert); + } + + InsertItem(index, item); + } + + public bool Remove(T item) + { + if (items.IsReadOnly) + { + ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection); + } + + int index = items.IndexOf(item); + if (index < 0) return false; + RemoveItem(index); + return true; + } + + public void RemoveAt(int index) + { + if (items.IsReadOnly) + { + ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection); + } + + if (index < 0 || index >= items.Count) + { + ThrowHelper.ThrowArgumentOutOfRange_IndexException(); + } + + RemoveItem(index); + } + + protected virtual void ClearItems() + { + items.Clear(); + } + + protected virtual void InsertItem(int index, T item) + { + items.Insert(index, item); + } + + protected virtual void RemoveItem(int index) + { + items.RemoveAt(index); + } + + protected virtual void SetItem(int index, T item) + { + items[index] = item; + } + + bool ICollection<T>.IsReadOnly + { + get + { + return items.IsReadOnly; + } + } + + IEnumerator IEnumerable.GetEnumerator() + { + return ((IEnumerable)items).GetEnumerator(); + } + + bool ICollection.IsSynchronized + { + get { return false; } + } + + object ICollection.SyncRoot + { + get + { + if (_syncRoot == null) + { + ICollection c = items as ICollection; + if (c != null) + { + _syncRoot = c.SyncRoot; + } + else + { + System.Threading.Interlocked.CompareExchange<Object>(ref _syncRoot, new Object(), null); + } + } + return _syncRoot; + } + } + + void ICollection.CopyTo(Array array, int index) + { + if (array == null) + { + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); + } + + if (array.Rank != 1) + { + ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_RankMultiDimNotSupported); + } + + if (array.GetLowerBound(0) != 0) + { + ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_NonZeroLowerBound); + } + + if (index < 0) + { + ThrowHelper.ThrowIndexArgumentOutOfRange_NeedNonNegNumException(); + } + + if (array.Length - index < Count) + { + ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall); + } + + T[] tArray = array as T[]; + if (tArray != null) + { + items.CopyTo(tArray, index); + } + else + { + // + // Catch the obvious case assignment will fail. + // We can't find all possible problems by doing the check though. + // For example, if the element type of the Array is derived from T, + // we can't figure out if we can successfully copy the element beforehand. + // + Type targetType = array.GetType().GetElementType(); + Type sourceType = typeof(T); + if (!(targetType.IsAssignableFrom(sourceType) || sourceType.IsAssignableFrom(targetType))) + { + ThrowHelper.ThrowArgumentException_Argument_InvalidArrayType(); + } + + // + // We can't cast array of value type to object[], so we don't support + // widening of primitive types here. + // + object[] objects = array as object[]; + if (objects == null) + { + ThrowHelper.ThrowArgumentException_Argument_InvalidArrayType(); + } + + int count = items.Count; + try + { + for (int i = 0; i < count; i++) + { + objects[index++] = items[i]; + } + } + catch (ArrayTypeMismatchException) + { + ThrowHelper.ThrowArgumentException_Argument_InvalidArrayType(); + } + } + } + + object IList.this[int index] + { + get { return items[index]; } + set + { + ThrowHelper.IfNullAndNullsAreIllegalThenThrow<T>(value, ExceptionArgument.value); + + try + { + this[index] = (T)value; + } + catch (InvalidCastException) + { + ThrowHelper.ThrowWrongValueTypeArgumentException(value, typeof(T)); + } + } + } + + bool IList.IsReadOnly + { + get + { + return items.IsReadOnly; + } + } + + bool IList.IsFixedSize + { + get + { + // There is no IList<T>.IsFixedSize, so we must assume that only + // readonly collections are fixed size, if our internal item + // collection does not implement IList. Note that Array implements + // IList, and therefore T[] and U[] will be fixed-size. + IList list = items as IList; + if (list != null) + { + return list.IsFixedSize; + } + return items.IsReadOnly; + } + } + + int IList.Add(object value) + { + if (items.IsReadOnly) + { + ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection); + } + ThrowHelper.IfNullAndNullsAreIllegalThenThrow<T>(value, ExceptionArgument.value); + + try + { + Add((T)value); + } + catch (InvalidCastException) + { + ThrowHelper.ThrowWrongValueTypeArgumentException(value, typeof(T)); + } + + return this.Count - 1; + } + + bool IList.Contains(object value) + { + if (IsCompatibleObject(value)) + { + return Contains((T)value); + } + return false; + } + + int IList.IndexOf(object value) + { + if (IsCompatibleObject(value)) + { + return IndexOf((T)value); + } + return -1; + } + + void IList.Insert(int index, object value) + { + if (items.IsReadOnly) + { + ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection); + } + ThrowHelper.IfNullAndNullsAreIllegalThenThrow<T>(value, ExceptionArgument.value); + + try + { + Insert(index, (T)value); + } + catch (InvalidCastException) + { + ThrowHelper.ThrowWrongValueTypeArgumentException(value, typeof(T)); + } + } + + void IList.Remove(object value) + { + if (items.IsReadOnly) + { + ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection); + } + + if (IsCompatibleObject(value)) + { + Remove((T)value); + } + } + + private static bool IsCompatibleObject(object value) + { + // Non-null values are fine. Only accept nulls if T is a class or Nullable<U>. + // Note that default(T) is not equal to null for value types except when T is Nullable<U>. + return ((value is T) || (value == null && default(T) == null)); + } + } +} |