using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using JD.Collections.Details;
using JD.Collections.Utilities;
using JD.Kernel.StaticHelpers;
namespace JD.Collections.ObjectModel
{
///
/// ReadOnlyCollectionBase is a base class that can be used to more easily implement the
/// generic ICollection<T> and non-generic ICollection interfaces for a read-only collection:
/// a collection that does not allow adding or removing elements.
///
///
/// To use ReadOnlyCollectionBase as a base class, the derived class must override
/// the Count and GetEnumerator methods.
/// ICollection<T>.Contains need not be implemented by the
/// derived class, but it should be strongly considered, because the ReadOnlyCollectionBase implementation
/// may not be very efficient.
///
/// The item type of the collection.
[Serializable]
[DebuggerDisplay("Count = {Count}"), DebuggerTypeProxy(typeof(ReadOnlyCollectionBase<>.DebugView))]
public abstract class ReadOnlyCollectionBase : ICollection, ICollection
{
#region Inner Types
private sealed class DebugView
{
#region Variables
private readonly ICollection m_collection;
#endregion
#region Constructor
///
/// Constructor.
///
///
public DebugView(ICollection collection)
{
Throw.IfNull(collection, "collection");
m_collection = collection;
}
#endregion
#region Properties
///
/// Items.
///
[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
public T[] Items
{
get
{
T[] array = new T[m_collection.Count];
m_collection.CopyTo(array, 0);
return array;
}
}
#endregion
}
#endregion
#region Methods
///
/// Throws an NotSupportedException stating that this collection cannot be modified.
///
protected virtual void MethodModifiesCollection()
{
throw new NotSupportedException(string.Format(Strings.CannotModifyCollection, GetSimpleClassName(GetType())));
}
///
/// Returns the simple name of the class, for use in exception messages.
///
/// The simple name of this class.
private static string GetSimpleClassName(Type type)
{
string name = type.Name;
// Just use the simple name.
int index = name.IndexOfAny(new [] { '<', '{', '`' });
if (index >= 0)
{
name = name.Substring(0, index);
}
return name;
}
///
/// Overriden.
///
///
public override string ToString()
{
return new CollectionPrinter().Print(this);
}
#endregion
#region ICollection Members
///
/// This method throws an NotSupportedException
/// stating the collection is read-only.
///
/// Item to be added to the collection.
/// Always thrown.
void ICollection.Add(T item)
{
MethodModifiesCollection();
}
///
/// This method throws an NotSupportedException
/// stating the collection is read-only.
///
/// Always thrown.
void ICollection.Clear()
{
MethodModifiesCollection();
}
///
/// This method throws an NotSupportedException
/// stating the collection is read-only.
///
/// Item to be removed from the collection.
/// Always thrown.
bool ICollection.Remove(T item)
{
MethodModifiesCollection();
return false;
}
///
/// Determines if the collection contains a particular item. This default implementation
/// iterates all of the items in the collection via GetEnumerator, testing each item
/// against using IComparable<T>.Equals or
/// Object.Equals.
///
/// You should strongly consider overriding this method to provide
/// a more efficient implementation.
/// The item to check for in the collection.
/// True if the collection contains , false otherwise.
public virtual bool Contains(T item)
{
IEqualityComparer equalityComparer = EqualityComparer.Default;
foreach (T i in this)
{
if (equalityComparer.Equals(i, item))
{
return true;
}
}
return false;
}
///
/// Copies all the items in the collection into an array. Implemented by
/// using the enumerator returned from GetEnumerator to get all the items
/// and copy them to the provided array.
///
/// Array to copy to.
/// Starting index in to copy to.
public virtual void CopyTo(T[] array, int arrayIndex)
{
int count = Count;
if (count == 0)
{
return;
}
Throw.IfNull(array, "array");
Throw.ArgumentOutOfRangeIf(count < 0, "count", Strings.ArgMustNotBeNegative);
Throw.ArgumentOutOfRangeIf(arrayIndex < 0, "arrayIndex", Strings.ArgMustNotBeNegative);
Throw.InvalidArgumentIf(arrayIndex >= array.Length || count > array.Length - arrayIndex, "arrayIndex", Strings.ArrayTooSmall);
int index = arrayIndex, i = 0;
foreach (T item in (ICollection)this)
{
if (i >= count)
{
break;
}
array[index] = item;
++index;
++i;
}
}
///
/// Creates an array of the correct size, and copies all the items in the
/// collection into the array, by calling CopyTo.
///
/// An array containing all the elements in the collection, in order.
public virtual T[] ToArray()
{
int count = Count;
T[] array = new T[count];
CopyTo(array, 0);
return array;
}
///
/// Must be overridden to provide the number of items in the collection.
///
/// The number of items in the collection.
public abstract int Count { get; }
///
/// Indicates whether the collection is read-only. Returns the value
/// of readOnly that was provided to the constructor.
///
/// Always true.
public bool IsReadOnly
{
get { return true; }
}
#endregion
#region IEnumerable Members
///
/// Must be overridden to enumerate all the members of the collection.
///
/// A generic IEnumerator<T> that can be used
/// to enumerate all the items in the collection.
public abstract IEnumerator GetEnumerator();
#endregion
#region ICollection Members
///
/// Copies all the items in the collection into an array. Implemented by
/// using the enumerator returned from GetEnumerator to get all the items
/// and copy them to the provided array.
///
/// Array to copy to.
/// Starting index in to copy to.
void ICollection.CopyTo(Array array, int index)
{
int count = Count;
if (count == 0)
{
return;
}
Throw.IfNull(array, "array");
Throw.ArgumentOutOfRangeIf(count < 0, "count", Strings.ArgMustNotBeNegative);
Throw.ArgumentOutOfRangeIf(index < 0, "arrayIndex", Strings.ArgMustNotBeNegative);
Throw.InvalidArgumentIf(index >= array.Length || count > array.Length - index, "arrayIndex", Strings.ArrayTooSmall);
int i = 0;
foreach (object o in (ICollection)this)
{
if (i >= count)
{
break;
}
array.SetValue(o, index);
++index;
++i;
}
}
///
/// Indicates whether the collection is synchronized.
///
/// Always returns false, indicating that the collection is not synchronized.
bool ICollection.IsSynchronized
{
get { return false; }
}
///
/// Indicates the synchronization object for this collection.
///
/// Always returns this.
object ICollection.SyncRoot
{
get { return this; }
}
#endregion
#region IEnumerable Members
///
/// Provides an IEnumerator that can be used to iterate all the members of the
/// collection. This implementation uses the IEnumerator<T> that was overridden
/// by the derived classes to enumerate the members of the collection.
///
/// An IEnumerator that can be used to iterate the collection.
IEnumerator IEnumerable.GetEnumerator()
{
foreach (T item in this)
{
yield return item;
}
}
#endregion
#region Debugger display
///
/// Display the contents of the collection in the debugger. This is intentionally private, it is called
/// only from the debugger due to the presence of the DebuggerDisplay attribute. It is similar
/// format to ToString(), but is limited to 250-300 characters or so, so as not to overload the debugger.
///
/// The string representation of the items in the collection, similar in format to ToString().
internal string DebuggerDisplayString()
{
const int MAXLENGTH = 250;
System.Text.StringBuilder builder = new System.Text.StringBuilder();
builder.Append('{');
// Call ToString on each item and put it in.
bool firstItem = true;
foreach (T item in this)
{
if (builder.Length >= MAXLENGTH)
{
builder.Append(", ...");
break;
}
if (!firstItem)
builder.Append(", ");
if (ReferenceEquals(item, null))
builder.Append("null");
else
builder.Append(item.ToString());
firstItem = false;
}
builder.Append('}');
return builder.ToString();
}
#endregion
}
}