334 lines
11 KiB
C#
334 lines
11 KiB
C#
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
|
|
{
|
|
/// <summary>
|
|
/// CollectionBase is a base class that can be used to more easily implement the
|
|
/// generic ICollection<T> and non-generic ICollection interfaces.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>To use CollectionBase as a base class, the derived class must override
|
|
/// the <see cref="Count"/>, <see cref="GetEnumerator"/>, <see cref="Add"/>, <see cref="Clear"/>, and <see cref="Remove"/> methods. </para>
|
|
/// <para><see cref="ICollection{T}.Contains"/> need not be implemented by the
|
|
/// derived class, but it should be strongly considered, because the CollectionBase implementation
|
|
/// may not be very efficient.</para>
|
|
/// </remarks>
|
|
/// <typeparam name="T">The item type of the collection.</typeparam>
|
|
[Serializable]
|
|
[DebuggerDisplay("Count = {Count}"), DebuggerTypeProxy(typeof(CollectionBase<>.DebugView))]
|
|
public abstract class CollectionBase<T> : ICollection<T>, ICollection
|
|
{
|
|
#region Inner Types
|
|
|
|
private sealed class DebugView
|
|
{
|
|
#region Variables
|
|
|
|
private readonly ICollection<T> m_collection;
|
|
|
|
#endregion
|
|
|
|
#region Constructor
|
|
|
|
/// <summary>
|
|
/// Constructor.
|
|
/// </summary>
|
|
/// <param name="collection"></param>
|
|
public DebugView(CollectionBase<T> collection)
|
|
{
|
|
Throw.IfNull(collection, "collection");
|
|
m_collection = collection;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Properties
|
|
|
|
/// <summary>
|
|
/// Items.
|
|
/// </summary>
|
|
[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
|
|
public T[] Items
|
|
{
|
|
get
|
|
{
|
|
T[] array = new T[m_collection.Count];
|
|
m_collection.CopyTo(array, 0);
|
|
return array;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Constructor
|
|
|
|
/// <summary>
|
|
/// Creates a new CollectionBase.
|
|
/// </summary>
|
|
protected CollectionBase()
|
|
{
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Misc members
|
|
|
|
/// <summary>
|
|
/// Shows the string representation of the collection. The string representation contains
|
|
/// a list of the items in the collection. Contained collections (except strings) are expanded
|
|
/// recursively.
|
|
/// </summary>
|
|
/// <returns>The string representation of the collection.</returns>
|
|
public override string ToString()
|
|
{
|
|
return new CollectionPrinter().Print(this);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Displays 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.
|
|
/// </summary>
|
|
/// <returns>The string representation of the items in the collection, similar in format to ToString().</returns>
|
|
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 (item == null)
|
|
builder.Append("null");
|
|
else
|
|
builder.Append(item.ToString());
|
|
|
|
firstItem = false;
|
|
}
|
|
|
|
builder.Append('}');
|
|
return builder.ToString();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ICollection<T> Members
|
|
|
|
/// <summary>
|
|
/// Must be overridden to allow adding items to this collection.
|
|
/// </summary>
|
|
/// <param name="item">Item to be added to the collection.</param>
|
|
public abstract void Add(T item);
|
|
|
|
/// <summary>
|
|
/// Must be overridden to allow clearing this collection.
|
|
/// </summary>
|
|
public abstract void Clear();
|
|
|
|
/// <summary>
|
|
/// Must be overridden to allow removing items from this collection.
|
|
/// </summary>
|
|
/// <returns>True if <paramref name="item"/> existed in the collection and
|
|
/// was removed. False if <paramref name="item"/> did not exist in the collection.</returns>
|
|
public abstract bool Remove(T item);
|
|
|
|
/// <summary>
|
|
/// 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 <paramref name="item"/> using IComparable<T>.Equals or
|
|
/// Object.Equals.
|
|
/// </summary>
|
|
/// <remarks>You should strongly consider overriding this method to provide
|
|
/// a more efficient implementation, or if the default equality comparison
|
|
/// is inappropriate.</remarks>
|
|
/// <param name="item">The item to check for in the collection.</param>
|
|
/// <returns>True if the collection contains <paramref name="item"/>, false otherwise.</returns>
|
|
public virtual bool Contains(T item)
|
|
{
|
|
IEqualityComparer<T> equalityComparer = EqualityComparer<T>.Default;
|
|
foreach (T i in this)
|
|
{
|
|
if (equalityComparer.Equals(i, item))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 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.
|
|
/// </summary>
|
|
/// <param name="array">Array to copy to.</param>
|
|
/// <param name="arrayIndex">Starting index in <paramref name="array"/> to copy to.</param>
|
|
public virtual void CopyTo(T[] array, int arrayIndex)
|
|
{
|
|
int count = this.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, "array", Strings.ArrayTooSmall);
|
|
|
|
int index = arrayIndex, i = 0;
|
|
foreach (T item in this)
|
|
{
|
|
if (i >= count)
|
|
{
|
|
break;
|
|
}
|
|
|
|
array[index] = item;
|
|
++index;
|
|
++i;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates an array of the correct size, and copies all the items in the
|
|
/// collection into the array, by calling CopyTo.
|
|
/// </summary>
|
|
/// <returns>An array containing all the elements in the collection, in order.</returns>
|
|
public virtual T[] ToArray()
|
|
{
|
|
int count = this.Count;
|
|
|
|
T[] array = new T[count];
|
|
CopyTo(array, 0);
|
|
return array;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Must be overridden to provide the number of items in the collection.
|
|
/// </summary>
|
|
/// <value>The number of items in the collection.</value>
|
|
public abstract int Count { get; }
|
|
|
|
/// <summary>
|
|
/// Indicates whether the collection is read-only. Always returns false.
|
|
/// </summary>
|
|
/// <value>Always returns false.</value>
|
|
bool ICollection<T>.IsReadOnly
|
|
{
|
|
get { return IsReadOnly; }
|
|
}
|
|
|
|
protected virtual bool IsReadOnly
|
|
{
|
|
get { return false; }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region IEnumerable<T> Members
|
|
|
|
/// <summary>
|
|
/// Must be overridden to enumerate all the members of the collection.
|
|
/// </summary>
|
|
/// <returns>A generic <see cref="IEnumerator{T}"/> that can be used to enumerate all the items in the collection.</returns>
|
|
public abstract IEnumerator<T> GetEnumerator();
|
|
|
|
#endregion
|
|
|
|
#region ICollection Members
|
|
|
|
/// <summary>
|
|
/// 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.
|
|
/// </summary>
|
|
/// <param name="array">Array to copy to.</param>
|
|
/// <param name="index">Starting index in <paramref name="array"/> to copy to.</param>
|
|
void ICollection.CopyTo(Array array, int index)
|
|
{
|
|
int count = this.Count;
|
|
|
|
if (count == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Throw.IfNull(array, "array");
|
|
Throw.ArgumentOutOfRangeIf(index < 0, "index", Strings.ArgMustNotBeNegative);
|
|
Throw.ArgumentOutOfRangeIf(index >= array.Length || count > array.Length - index, "index", Strings.ArrayTooSmall);
|
|
|
|
int i = 0;
|
|
foreach (object o in this)
|
|
{
|
|
if (i >= count)
|
|
{
|
|
break;
|
|
}
|
|
|
|
array.SetValue(o, index);
|
|
++index;
|
|
++i;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Indicates whether the collection is synchronized.
|
|
/// </summary>
|
|
/// <value>Always returns false, indicating that the collection is not synchronized.</value>
|
|
bool ICollection.IsSynchronized
|
|
{
|
|
get { return false; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Indicates the synchronization object for this collection.
|
|
/// </summary>
|
|
/// <value>Always returns this.</value>
|
|
object ICollection.SyncRoot
|
|
{
|
|
get { return this; }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region IEnumerable Members
|
|
|
|
/// <summary>
|
|
/// 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.
|
|
/// </summary>
|
|
/// <returns>An IEnumerator that can be used to iterate the collection.</returns>
|
|
IEnumerator IEnumerable.GetEnumerator()
|
|
{
|
|
return GetEnumerator();
|
|
}
|
|
|
|
#endregion
|
|
|
|
}
|
|
}
|