Почему коллекция ReadOnlyCollection <T>не является списком ReadOnlyList <T>? - PullRequest
4 голосов
/ 12 мая 2011

Я думал, IEnumerable вещи - это объекты, которые вы можете перебирать.
Если они также ICollection s, вы знаете, сколько там элементов.
А если они равны IList s, то выможет взять содержащие объекты из определенного индекса.

A ReadOnlyCollection<T> реализует IList<T>.Так не будет ли ReadOnlyList<T> лучшим именем.

И есть ли в фреймворке настоящий ReadOnlyCollection<T>?
(Так что мне не нужен IList для создания такогооболочка только для чтения)

Ответы [ 2 ]

0 голосов
/ 12 мая 2011
namespace System.Collections.ObjectModel
{
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Runtime.InteropServices;
    using System.Threading;

    internal sealed class CollectionDebugView<T>
    {
        private readonly ICollection<T> collection;

        public CollectionDebugView(ICollection<T> collection)
        {
            if (collection == null) { throw new ArgumentNullException("collection"); }

            this.collection = collection;
        }

        [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
        public T[] Items
        {
            get
            {
                T[] items = new T[this.collection.Count];
                this.collection.CopyTo(items, 0);
                return items;
            }
        }
    }

    [Serializable]
    [ComVisible(false)]
    [DebuggerDisplay("Count = {Count}")]
    [DebuggerTypeProxy(typeof(CollectionDebugView<>))]
    public class ReadOnlyCollection<T> : ICollection<T>, ICollection
    {
        private readonly ICollection<T> genericCollection;
        private readonly ICollection nongenericCollection;

        [NonSerialized]
        private object syncRoot;

        public ReadOnlyCollection(ICollection<T> collection)
        {
            if (collection == null) { throw new ArgumentNullException("collection"); }

            this.genericCollection = collection;
            this.nongenericCollection = collection as ICollection;
        }

        void ICollection<T>.Add(T item)
        {
            throw new NotSupportedException();
        }

        void ICollection<T>.Clear()
        {
            throw new NotSupportedException();
        }

        public bool Contains(T item)
        {
            return this.genericCollection.Contains(item);
        }

        public void CopyTo(T[] array, int arrayIndex)
        {
            this.genericCollection.CopyTo(array, arrayIndex);
        }

        public int Count
        {
            get { return this.genericCollection.Count; }
        }

        public bool IsReadOnly
        {
            get { return true; }
        }

        bool ICollection<T>.Remove(T item)
        {
            throw new NotSupportedException();
        }

        public IEnumerator<T> GetEnumerator()
        {
            return this.genericCollection.GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return ((IEnumerable)this.genericCollection).GetEnumerator();
        }

        void ICollection.CopyTo(Array array, int index)
        {
            if (this.nongenericCollection == null)
            {
                if (array == null) { throw new ArgumentNullException("array"); }
                if (array.Rank != 1) { throw new ArgumentException(); }
                if (array.GetLowerBound(0) != 0) { throw new ArgumentException(); }
                if (index < 0) { throw new ArgumentOutOfRangeException(); }
                if (array.Length < index + this.genericCollection.Count) { throw new ArgumentException(); }

                T[] typedArray = array as T[];

                if (typedArray == null)
                {
                    Type arrayType = array.GetType().GetElementType();
                    Type collectionType = typeof(T);

                    if (arrayType.IsAssignableFrom(collectionType) || collectionType.IsAssignableFrom(arrayType))
                    {
                        object[] objectArray = array as object[];

                        if (objectArray == null) { throw new ArgumentException(); }

                        try
                        {
                            foreach (T item in this.genericCollection)
                            {
                                objectArray[index] = item;
                                index++;
                            }
                        }
                        catch (ArrayTypeMismatchException)
                        {
                            throw new ArgumentException();
                        }

                    }
                    else
                    {
                        throw new ArgumentException();
                    }
                }
                else
                {
                    this.genericCollection.CopyTo(typedArray, index);
                }
            }
            else
            {
                this.nongenericCollection.CopyTo(array, index);
            }
        }

        int ICollection.Count
        {
            get { return this.nongenericCollection == null ? this.genericCollection.Count : this.nongenericCollection.Count; }
        }

        bool ICollection.IsSynchronized
        {
            get { return this.nongenericCollection == null ? false : this.nongenericCollection.IsSynchronized; }
        }

        object ICollection.SyncRoot
        {
            get
            {
                if (this.syncRoot == null)
                {
                    if (this.nongenericCollection == null)
                    {
                        this.syncRoot = this.nongenericCollection.SyncRoot;
                    }
                    else
                    {
                        Interlocked.CompareExchange<object>(ref this.syncRoot, new object(), null);
                    }
                }

                return this.syncRoot;
            }
        }
    }
}
0 голосов
/ 12 мая 2011

Поскольку ReadOnlyCollection<T> является просто оболочкой для IList<T>, которая запрещает изменение списка, должно быть очень просто сгенерировать подобную оболочку для ICollection<T>:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading;

class MyReadOnlyCollection<T> : ICollection<T>, IEnumerable<T>, ICollection, IEnumerable
{
    private ICollection<T> _collection;
    private object _syncRoot;

    public MyReadOnlyCollection(ICollection<T> collection)
    {
        _collection = collection;
    }


    public void Add(T item)
    {
        throw new NotSupportedException("Trying to modify a read-only collection.");
    }

    public void Clear()
    {
        throw new NotSupportedException("Trying to modify a read-only collection.");
    }

    public bool Contains(T item)
    {
        return _collection.Contains(item);
    }

    public void CopyTo(T[] array, int arrayIndex)
    {
        _collection.CopyTo(array, arrayIndex);
    }

    public int Count
    {
        get { return _collection.Count; }
    }

    public bool IsReadOnly
    {
        get { return true; }
    }

    public bool Remove(T item)
    {
        throw new NotSupportedException("Trying to modify a read-only collection.");
    }

    public IEnumerator<T> GetEnumerator()
    {
        return _collection.GetEnumerator();
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return ((ICollection)_collection).GetEnumerator();
    }

    public void CopyTo(Array array, int index)
    {
        ((ICollection)_collection).CopyTo(array, index);
    }

    public bool IsSynchronized
    {
        get { return false; }
    }

    public object SyncRoot
    {
        get
        {
            if (_syncRoot == null)
            {
                ICollection list = _collection as ICollection;
                if (list != null)
                {
                    _syncRoot = list.SyncRoot;
                }
                else
                {
                    Interlocked.CompareExchange(ref _syncRoot, new object(), null);
                }
            }
            return _syncRoot;
        }
    }
}
...