e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
837 lines
30 KiB
C#
837 lines
30 KiB
C#
//------------------------------------------------------------------------------
|
|
// <copyright file="NameObjectCollectionBase.cs" company="Microsoft">
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
// </copyright>
|
|
//------------------------------------------------------------------------------
|
|
|
|
/*
|
|
* Ordered String/Object collection of name/value pairs with support for null key
|
|
*
|
|
* This class is intended to be used as a base class
|
|
*
|
|
* Copyright (c) 2000 Microsoft Corporation
|
|
*/
|
|
|
|
namespace System.Collections.Specialized {
|
|
|
|
using Microsoft.Win32;
|
|
using System.Collections;
|
|
using System.Diagnostics.CodeAnalysis;
|
|
using System.Globalization;
|
|
using System.Runtime.Serialization;
|
|
using System.Security.Permissions;
|
|
|
|
|
|
/// <devdoc>
|
|
/// <para>Provides the <see langword='abstract '/>base class for a sorted collection of associated <see cref='System.String' qualify='true'/> keys
|
|
/// and <see cref='System.Object' qualify='true'/> values that can be accessed either with the hash code of
|
|
/// the key or with the index.</para>
|
|
/// </devdoc>
|
|
[Serializable()]
|
|
public abstract class NameObjectCollectionBase : ICollection, ISerializable, IDeserializationCallback {
|
|
// const names used for serialization
|
|
private const String ReadOnlyName = "ReadOnly";
|
|
private const String CountName = "Count";
|
|
private const String ComparerName = "Comparer";
|
|
private const String HashCodeProviderName = "HashProvider";
|
|
private const String KeysName = "Keys";
|
|
private const String ValuesName = "Values";
|
|
private const String KeyComparerName = "KeyComparer";
|
|
private const String VersionName = "Version";
|
|
|
|
private bool _readOnly = false;
|
|
private ArrayList _entriesArray;
|
|
private IEqualityComparer _keyComparer;
|
|
private volatile Hashtable _entriesTable;
|
|
private volatile NameObjectEntry _nullKeyEntry;
|
|
private KeysCollection _keys;
|
|
private SerializationInfo _serializationInfo;
|
|
private int _version;
|
|
[NonSerialized]
|
|
private Object _syncRoot;
|
|
|
|
private static StringComparer defaultComparer = StringComparer.InvariantCultureIgnoreCase;
|
|
|
|
/// <devdoc>
|
|
/// <para> Creates an empty <see cref='System.Collections.Specialized.NameObjectCollectionBase'/> instance with the default initial capacity and using the default case-insensitive hash
|
|
/// code provider and the default case-insensitive comparer.</para>
|
|
/// </devdoc>
|
|
protected NameObjectCollectionBase() :this(defaultComparer) {
|
|
}
|
|
|
|
protected NameObjectCollectionBase(IEqualityComparer equalityComparer)
|
|
{
|
|
_keyComparer = (equalityComparer == null) ? defaultComparer : equalityComparer;
|
|
Reset();
|
|
}
|
|
|
|
protected NameObjectCollectionBase(Int32 capacity, IEqualityComparer equalityComparer) : this (equalityComparer)
|
|
{
|
|
Reset(capacity);
|
|
}
|
|
|
|
|
|
/// <devdoc>
|
|
/// <para>Creates an empty <see cref='System.Collections.Specialized.NameObjectCollectionBase'/> instance with
|
|
/// the default initial capacity and using the specified case-insensitive hash code provider and the
|
|
/// specified case-insensitive comparer.</para>
|
|
/// </devdoc>
|
|
|
|
#pragma warning disable 618
|
|
[Obsolete("Please use NameObjectCollectionBase(IEqualityComparer) instead.")]
|
|
protected NameObjectCollectionBase(IHashCodeProvider hashProvider, IComparer comparer) {
|
|
_keyComparer = new CompatibleComparer( comparer, hashProvider);
|
|
Reset();
|
|
}
|
|
#pragma warning restore 618
|
|
|
|
/// <devdoc>
|
|
/// <para>Creates an empty <see cref='System.Collections.Specialized.NameObjectCollectionBase'/> instance with the specified
|
|
/// initial capacity and using the specified case-insensitive hash code provider
|
|
/// and the specified case-insensitive comparer.</para>
|
|
/// </devdoc>
|
|
#pragma warning disable 618
|
|
[Obsolete("Please use NameObjectCollectionBase(Int32, IEqualityComparer) instead.")]
|
|
protected NameObjectCollectionBase(int capacity, IHashCodeProvider hashProvider, IComparer comparer) {
|
|
_keyComparer = new CompatibleComparer( comparer, hashProvider);
|
|
Reset(capacity);
|
|
}
|
|
#pragma warning restore 618
|
|
|
|
/// <devdoc>
|
|
/// <para>Creates an empty <see cref='System.Collections.Specialized.NameObjectCollectionBase'/> instance with the specified
|
|
/// initial capacity and using the default case-insensitive hash code provider
|
|
/// and the default case-insensitive comparer.</para>
|
|
/// </devdoc>
|
|
protected NameObjectCollectionBase(int capacity) {
|
|
_keyComparer = StringComparer.InvariantCultureIgnoreCase;
|
|
Reset(capacity);
|
|
}
|
|
|
|
// Allow internal extenders to avoid creating the hashtable/arraylist.
|
|
internal NameObjectCollectionBase(DBNull dummy)
|
|
{
|
|
}
|
|
|
|
//
|
|
// Serialization support
|
|
//
|
|
|
|
/// <devdoc>
|
|
/// <para>[To be supplied.]</para>
|
|
/// </devdoc>
|
|
protected NameObjectCollectionBase(SerializationInfo info, StreamingContext context) {
|
|
_serializationInfo = info;
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// <para>[To be supplied.]</para>
|
|
/// </devdoc>
|
|
[SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase", Justification = "System.dll is still using pre-v4 security model and needs this demand")]
|
|
[SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.SerializationFormatter)]
|
|
public virtual void GetObjectData(SerializationInfo info, StreamingContext context) {
|
|
if (info == null)
|
|
throw new ArgumentNullException("info");
|
|
|
|
info.AddValue(ReadOnlyName, _readOnly);
|
|
|
|
#pragma warning disable 618
|
|
// Maintain backward serialization compatibility if new APIs are not used.
|
|
if( _keyComparer == defaultComparer) {
|
|
info.AddValue(HashCodeProviderName, CompatibleComparer.DefaultHashCodeProvider, typeof(IHashCodeProvider));
|
|
info.AddValue(ComparerName, CompatibleComparer.DefaultComparer, typeof(IComparer));
|
|
}
|
|
else if(_keyComparer == null) {
|
|
info.AddValue(HashCodeProviderName, null, typeof(IHashCodeProvider));
|
|
info.AddValue(ComparerName, null, typeof(IComparer));
|
|
}
|
|
else if(_keyComparer is CompatibleComparer) {
|
|
CompatibleComparer c = (CompatibleComparer)_keyComparer;
|
|
info.AddValue(HashCodeProviderName, c.HashCodeProvider, typeof(IHashCodeProvider));
|
|
info.AddValue(ComparerName, c.Comparer, typeof(IComparer));
|
|
}
|
|
else {
|
|
info.AddValue(KeyComparerName, _keyComparer, typeof(IEqualityComparer));
|
|
}
|
|
#pragma warning restore 618
|
|
|
|
int count = _entriesArray.Count;
|
|
info.AddValue(CountName, count);
|
|
|
|
String[] keys = new String[count];
|
|
Object[] values = new Object[count];
|
|
|
|
for (int i = 0; i < count; i++) {
|
|
NameObjectEntry entry = (NameObjectEntry)_entriesArray[i];
|
|
keys[i] = entry.Key;
|
|
values[i] = entry.Value;
|
|
}
|
|
|
|
info.AddValue(KeysName, keys, typeof(String[]));
|
|
info.AddValue(ValuesName, values, typeof(Object[]));
|
|
info.AddValue(VersionName, _version);
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// <para>[To be supplied.]</para>
|
|
/// </devdoc>
|
|
public virtual void OnDeserialization(Object sender) {
|
|
if (_keyComparer != null) {
|
|
return;//Somebody had a dependency on this hashtable and fixed us up before the ObjectManager got to it.
|
|
}
|
|
|
|
if (_serializationInfo == null)
|
|
throw new SerializationException();
|
|
|
|
SerializationInfo info = _serializationInfo;
|
|
_serializationInfo = null;
|
|
|
|
bool readOnly = false;
|
|
int count = 0;
|
|
String[] keys = null;
|
|
Object[] values = null;
|
|
#pragma warning disable 618
|
|
IHashCodeProvider hashProvider = null;
|
|
#pragma warning restore 618
|
|
IComparer comparer = null;
|
|
bool hasVersion = false;
|
|
int serializedVersion = 0;
|
|
|
|
SerializationInfoEnumerator enumerator = info.GetEnumerator();
|
|
while( enumerator.MoveNext())
|
|
{
|
|
switch( enumerator.Name)
|
|
{
|
|
case ReadOnlyName:
|
|
readOnly = info.GetBoolean(ReadOnlyName);;
|
|
break;
|
|
case HashCodeProviderName:
|
|
#pragma warning disable 618
|
|
hashProvider = (IHashCodeProvider)info.GetValue(HashCodeProviderName, typeof(IHashCodeProvider));;
|
|
#pragma warning restore 618
|
|
break;
|
|
case ComparerName:
|
|
comparer = (IComparer)info.GetValue(ComparerName, typeof(IComparer));
|
|
break;
|
|
case KeyComparerName:
|
|
_keyComparer = (IEqualityComparer)info.GetValue(KeyComparerName, typeof(IEqualityComparer));
|
|
break;
|
|
case CountName:
|
|
count = info.GetInt32(CountName);
|
|
break;
|
|
case KeysName:
|
|
keys = (String[])info.GetValue(KeysName, typeof(String[]));
|
|
break;
|
|
case ValuesName:
|
|
values = (Object[])info.GetValue(ValuesName, typeof(Object[]));
|
|
break;
|
|
case VersionName:
|
|
hasVersion = true;
|
|
serializedVersion = info.GetInt32(VersionName);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if( _keyComparer == null) {
|
|
if(comparer == null || hashProvider == null)
|
|
{
|
|
throw new SerializationException();
|
|
}
|
|
else {
|
|
// create a new key comparer for V1 Object
|
|
_keyComparer = new CompatibleComparer(comparer, hashProvider);
|
|
}
|
|
}
|
|
|
|
if ( keys == null || values == null)
|
|
throw new SerializationException();
|
|
|
|
Reset(count);
|
|
|
|
for (int i = 0; i < count; i++)
|
|
BaseAdd(keys[i], values[i]);
|
|
|
|
_readOnly = readOnly; // after collection populated
|
|
if(hasVersion) {
|
|
_version = serializedVersion;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Private helpers
|
|
//
|
|
|
|
private void Reset() {
|
|
_entriesArray = new ArrayList();
|
|
_entriesTable = new Hashtable(_keyComparer);
|
|
_nullKeyEntry = null;
|
|
_version++;
|
|
}
|
|
|
|
private void Reset(int capacity) {
|
|
_entriesArray = new ArrayList(capacity);
|
|
_entriesTable = new Hashtable(capacity, _keyComparer);
|
|
_nullKeyEntry = null;
|
|
_version++;
|
|
}
|
|
|
|
private NameObjectEntry FindEntry(String key) {
|
|
if (key != null)
|
|
return (NameObjectEntry)_entriesTable[key];
|
|
else
|
|
return _nullKeyEntry;
|
|
}
|
|
|
|
internal IEqualityComparer Comparer
|
|
{
|
|
get
|
|
{
|
|
return _keyComparer;
|
|
}
|
|
set
|
|
{
|
|
_keyComparer = value;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/// <devdoc>
|
|
/// <para>Gets or sets a value indicating whether the <see cref='System.Collections.Specialized.NameObjectCollectionBase'/> instance is read-only.</para>
|
|
/// </devdoc>
|
|
protected bool IsReadOnly {
|
|
get { return _readOnly; }
|
|
set { _readOnly = value; }
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// <para>Gets a value indicating whether the <see cref='System.Collections.Specialized.NameObjectCollectionBase'/> instance contains entries whose
|
|
/// keys are not <see langword='null'/>.</para>
|
|
/// </devdoc>
|
|
protected bool BaseHasKeys() {
|
|
return (_entriesTable.Count > 0); // any entries with keys?
|
|
}
|
|
|
|
//
|
|
// Methods to add / remove entries
|
|
//
|
|
|
|
/// <devdoc>
|
|
/// <para>Adds an entry with the specified key and value into the
|
|
/// <see cref='System.Collections.Specialized.NameObjectCollectionBase'/> instance.</para>
|
|
/// </devdoc>
|
|
protected void BaseAdd(String name, Object value) {
|
|
if (_readOnly)
|
|
throw new NotSupportedException(SR.GetString(SR.CollectionReadOnly));
|
|
|
|
NameObjectEntry entry = new NameObjectEntry(name, value);
|
|
|
|
// insert entry into hashtable
|
|
if (name != null) {
|
|
if (_entriesTable[name] == null)
|
|
_entriesTable.Add(name, entry);
|
|
}
|
|
else { // null key -- special case -- hashtable doesn't like null keys
|
|
if (_nullKeyEntry == null)
|
|
_nullKeyEntry = entry;
|
|
}
|
|
|
|
// add entry to the list
|
|
_entriesArray.Add(entry);
|
|
|
|
_version++;
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// <para>Removes the entries with the specified key from the
|
|
/// <see cref='System.Collections.Specialized.NameObjectCollectionBase'/> instance.</para>
|
|
/// </devdoc>
|
|
protected void BaseRemove(String name) {
|
|
if (_readOnly)
|
|
throw new NotSupportedException(SR.GetString(SR.CollectionReadOnly));
|
|
|
|
if (name != null) {
|
|
// remove from hashtable
|
|
_entriesTable.Remove(name);
|
|
|
|
// remove from array
|
|
for (int i = _entriesArray.Count-1; i >= 0; i--) {
|
|
if (_keyComparer.Equals(name, BaseGetKey(i)))
|
|
_entriesArray.RemoveAt(i);
|
|
}
|
|
}
|
|
else { // null key -- special case
|
|
// null out special 'null key' entry
|
|
_nullKeyEntry = null;
|
|
|
|
// remove from array
|
|
for (int i = _entriesArray.Count-1; i >= 0; i--) {
|
|
if (BaseGetKey(i) == null)
|
|
_entriesArray.RemoveAt(i);
|
|
}
|
|
}
|
|
|
|
_version++;
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// <para> Removes the entry at the specified index of the
|
|
/// <see cref='System.Collections.Specialized.NameObjectCollectionBase'/> instance.</para>
|
|
/// </devdoc>
|
|
protected void BaseRemoveAt(int index) {
|
|
if (_readOnly)
|
|
throw new NotSupportedException(SR.GetString(SR.CollectionReadOnly));
|
|
|
|
String key = BaseGetKey(index);
|
|
|
|
if (key != null) {
|
|
// remove from hashtable
|
|
_entriesTable.Remove(key);
|
|
}
|
|
else { // null key -- special case
|
|
// null out special 'null key' entry
|
|
_nullKeyEntry = null;
|
|
}
|
|
|
|
// remove from array
|
|
_entriesArray.RemoveAt(index);
|
|
|
|
_version++;
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// <para>Removes all entries from the <see cref='System.Collections.Specialized.NameObjectCollectionBase'/> instance.</para>
|
|
/// </devdoc>
|
|
protected void BaseClear() {
|
|
if (_readOnly)
|
|
throw new NotSupportedException(SR.GetString(SR.CollectionReadOnly));
|
|
|
|
Reset();
|
|
}
|
|
|
|
//
|
|
// Access by name
|
|
//
|
|
|
|
/// <devdoc>
|
|
/// <para>Gets the value of the first entry with the specified key from
|
|
/// the <see cref='System.Collections.Specialized.NameObjectCollectionBase'/> instance.</para>
|
|
/// </devdoc>
|
|
protected Object BaseGet(String name) {
|
|
NameObjectEntry e = FindEntry(name);
|
|
return (e != null) ? e.Value : null;
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// <para>Sets the value of the first entry with the specified key in the <see cref='System.Collections.Specialized.NameObjectCollectionBase'/>
|
|
/// instance, if found; otherwise, adds an entry with the specified key and value
|
|
/// into the <see cref='System.Collections.Specialized.NameObjectCollectionBase'/>
|
|
/// instance.</para>
|
|
/// </devdoc>
|
|
protected void BaseSet(String name, Object value) {
|
|
if (_readOnly)
|
|
throw new NotSupportedException(SR.GetString(SR.CollectionReadOnly));
|
|
|
|
NameObjectEntry entry = FindEntry(name);
|
|
if (entry != null) {
|
|
entry.Value = value;
|
|
_version++;
|
|
}
|
|
else {
|
|
BaseAdd(name, value);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Access by index
|
|
//
|
|
|
|
/// <devdoc>
|
|
/// <para>Gets the value of the entry at the specified index of
|
|
/// the <see cref='System.Collections.Specialized.NameObjectCollectionBase'/> instance.</para>
|
|
/// </devdoc>
|
|
protected Object BaseGet(int index) {
|
|
NameObjectEntry entry = (NameObjectEntry)_entriesArray[index];
|
|
return entry.Value;
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// <para>Gets the key of the entry at the specified index of the
|
|
/// <see cref='System.Collections.Specialized.NameObjectCollectionBase'/>
|
|
/// instance.</para>
|
|
/// </devdoc>
|
|
protected String BaseGetKey(int index) {
|
|
NameObjectEntry entry = (NameObjectEntry)_entriesArray[index];
|
|
return entry.Key;
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// <para>Sets the value of the entry at the specified index of
|
|
/// the <see cref='System.Collections.Specialized.NameObjectCollectionBase'/> instance.</para>
|
|
/// </devdoc>
|
|
protected void BaseSet(int index, Object value) {
|
|
if (_readOnly)
|
|
throw new NotSupportedException(SR.GetString(SR.CollectionReadOnly));
|
|
|
|
NameObjectEntry entry = (NameObjectEntry)_entriesArray[index];
|
|
entry.Value = value;
|
|
_version++;
|
|
}
|
|
|
|
//
|
|
// ICollection implementation
|
|
//
|
|
|
|
/// <devdoc>
|
|
/// <para>Returns an enumerator that can iterate through the <see cref='System.Collections.Specialized.NameObjectCollectionBase'/>.</para>
|
|
/// </devdoc>
|
|
public virtual IEnumerator GetEnumerator() {
|
|
return new NameObjectKeysEnumerator(this);
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// <para>Gets the number of key-and-value pairs in the <see cref='System.Collections.Specialized.NameObjectCollectionBase'/> instance.</para>
|
|
/// </devdoc>
|
|
public virtual int Count {
|
|
get {
|
|
return _entriesArray.Count;
|
|
}
|
|
}
|
|
|
|
void ICollection.CopyTo(Array array, int index) {
|
|
if (array==null) {
|
|
throw new ArgumentNullException("array");
|
|
}
|
|
|
|
if (array.Rank != 1) {
|
|
throw new ArgumentException(SR.GetString(SR.Arg_MultiRank));
|
|
}
|
|
|
|
if (index < 0) {
|
|
throw new ArgumentOutOfRangeException("index",SR.GetString(SR.IndexOutOfRange, index.ToString(CultureInfo.CurrentCulture)) );
|
|
}
|
|
|
|
if (array.Length - index < _entriesArray.Count) {
|
|
throw new ArgumentException(SR.GetString(SR.Arg_InsufficientSpace));
|
|
}
|
|
|
|
for (IEnumerator e = this.GetEnumerator(); e.MoveNext();)
|
|
array.SetValue(e.Current, index++);
|
|
}
|
|
|
|
Object ICollection.SyncRoot {
|
|
get {
|
|
if( _syncRoot == null) {
|
|
System.Threading.Interlocked.CompareExchange(ref _syncRoot, new Object(), null);
|
|
}
|
|
return _syncRoot;
|
|
}
|
|
}
|
|
|
|
bool ICollection.IsSynchronized {
|
|
get { return false; }
|
|
}
|
|
|
|
//
|
|
// Helper methods to get arrays of keys and values
|
|
//
|
|
|
|
/// <devdoc>
|
|
/// <para>Returns a <see cref='System.String' qualify='true'/> array containing all the keys in the
|
|
/// <see cref='System.Collections.Specialized.NameObjectCollectionBase'/> instance.</para>
|
|
/// </devdoc>
|
|
protected String[] BaseGetAllKeys() {
|
|
int n = _entriesArray.Count;
|
|
String[] allKeys = new String[n];
|
|
|
|
for (int i = 0; i < n; i++)
|
|
allKeys[i] = BaseGetKey(i);
|
|
|
|
return allKeys;
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// <para>Returns an <see cref='System.Object' qualify='true'/> array containing all the values in the
|
|
/// <see cref='System.Collections.Specialized.NameObjectCollectionBase'/> instance.</para>
|
|
/// </devdoc>
|
|
protected Object[] BaseGetAllValues() {
|
|
int n = _entriesArray.Count;
|
|
Object[] allValues = new Object[n];
|
|
|
|
for (int i = 0; i < n; i++)
|
|
allValues[i] = BaseGet(i);
|
|
|
|
return allValues;
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// <para>Returns an array of the specified type containing
|
|
/// all the values in the <see cref='System.Collections.Specialized.NameObjectCollectionBase'/> instance.</para>
|
|
/// </devdoc>
|
|
protected object[] BaseGetAllValues(Type type) {
|
|
int n = _entriesArray.Count;
|
|
if (type == null) {
|
|
throw new ArgumentNullException("type");
|
|
}
|
|
object[] allValues = (object[]) SecurityUtils.ArrayCreateInstance(type, n);
|
|
|
|
for (int i = 0; i < n; i++) {
|
|
allValues[i] = BaseGet(i);
|
|
}
|
|
|
|
return allValues;
|
|
}
|
|
|
|
//
|
|
// Keys propetry
|
|
//
|
|
|
|
/// <devdoc>
|
|
/// <para>Returns a <see cref='System.Collections.Specialized.NameObjectCollectionBase.KeysCollection'/> instance containing
|
|
/// all the keys in the <see cref='System.Collections.Specialized.NameObjectCollectionBase'/> instance.</para>
|
|
/// </devdoc>
|
|
public virtual KeysCollection Keys {
|
|
get {
|
|
if (_keys == null)
|
|
_keys = new KeysCollection(this);
|
|
return _keys;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Simple entry class to allow substitution of values and indexed access to keys
|
|
//
|
|
|
|
internal class NameObjectEntry {
|
|
|
|
internal NameObjectEntry(String name, Object value) {
|
|
Key = name;
|
|
Value = value;
|
|
}
|
|
|
|
internal String Key;
|
|
internal Object Value;
|
|
}
|
|
|
|
//
|
|
// Enumerator over keys of NameObjectCollection
|
|
//
|
|
|
|
[Serializable()]
|
|
internal class NameObjectKeysEnumerator : IEnumerator {
|
|
private int _pos;
|
|
private NameObjectCollectionBase _coll;
|
|
private int _version;
|
|
|
|
internal NameObjectKeysEnumerator(NameObjectCollectionBase coll) {
|
|
_coll = coll;
|
|
_version = _coll._version;
|
|
_pos = -1;
|
|
}
|
|
|
|
public bool MoveNext() {
|
|
if ( _version != _coll._version)
|
|
throw new InvalidOperationException(SR.GetString(SR.InvalidOperation_EnumFailedVersion));
|
|
|
|
if( _pos < _coll.Count - 1) {
|
|
_pos++;
|
|
return true;
|
|
}
|
|
else {
|
|
_pos = _coll.Count;
|
|
return false;
|
|
}
|
|
|
|
}
|
|
|
|
public void Reset() {
|
|
if (_version != _coll._version)
|
|
throw new InvalidOperationException(SR.GetString(SR.InvalidOperation_EnumFailedVersion));
|
|
_pos = -1;
|
|
}
|
|
|
|
public Object Current {
|
|
get {
|
|
if(_pos >= 0 && _pos < _coll.Count) {
|
|
return _coll.BaseGetKey(_pos);
|
|
}
|
|
else {
|
|
throw new InvalidOperationException(SR.GetString(SR.InvalidOperation_EnumOpCantHappen));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Keys collection
|
|
//
|
|
|
|
/// <devdoc>
|
|
/// <para>Represents a collection of the <see cref='System.String' qualify='true'/> keys of a collection.</para>
|
|
/// </devdoc>
|
|
[Serializable()]
|
|
public class KeysCollection : ICollection {
|
|
|
|
private NameObjectCollectionBase _coll;
|
|
|
|
internal KeysCollection(NameObjectCollectionBase coll) {
|
|
_coll = coll;
|
|
}
|
|
|
|
// Indexed access
|
|
|
|
/// <devdoc>
|
|
/// <para> Gets the key at the specified index of the collection.</para>
|
|
/// </devdoc>
|
|
public virtual String Get(int index) {
|
|
return _coll.BaseGetKey(index);
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// <para>Represents the entry at the specified index of the collection.</para>
|
|
/// </devdoc>
|
|
public String this[int index] {
|
|
get {
|
|
return Get(index);
|
|
}
|
|
}
|
|
|
|
// ICollection implementation
|
|
|
|
/// <devdoc>
|
|
/// <para>Returns an enumerator that can iterate through the
|
|
/// <see cref='System.Collections.Specialized.NameObjectCollectionBase.KeysCollection'/>.</para>
|
|
/// </devdoc>
|
|
public IEnumerator GetEnumerator() {
|
|
return new NameObjectKeysEnumerator(_coll);
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// <para>Gets the number of keys in the <see cref='System.Collections.Specialized.NameObjectCollectionBase.KeysCollection'/>.</para>
|
|
/// </devdoc>
|
|
public int Count {
|
|
get {
|
|
return _coll.Count;
|
|
}
|
|
}
|
|
|
|
void ICollection.CopyTo(Array array, int index) {
|
|
if (array==null) {
|
|
throw new ArgumentNullException("array");
|
|
}
|
|
|
|
if (array.Rank != 1) {
|
|
throw new ArgumentException(SR.GetString(SR.Arg_MultiRank));
|
|
}
|
|
|
|
if (index < 0) {
|
|
throw new ArgumentOutOfRangeException("index",SR.GetString(SR.IndexOutOfRange, index.ToString(CultureInfo.CurrentCulture)) );
|
|
}
|
|
|
|
if (array.Length - index < _coll.Count) {
|
|
throw new ArgumentException(SR.GetString(SR.Arg_InsufficientSpace));
|
|
}
|
|
|
|
for (IEnumerator e = this.GetEnumerator(); e.MoveNext();)
|
|
array.SetValue(e.Current, index++);
|
|
}
|
|
|
|
Object ICollection.SyncRoot {
|
|
get { return ((ICollection)_coll).SyncRoot; }
|
|
}
|
|
|
|
|
|
bool ICollection.IsSynchronized {
|
|
get { return false; }
|
|
}
|
|
}
|
|
}
|
|
|
|
[Serializable()]
|
|
internal class CompatibleComparer: IEqualityComparer {
|
|
IComparer _comparer;
|
|
static volatile IComparer defaultComparer;
|
|
// Needed for compatability
|
|
#pragma warning disable 618
|
|
IHashCodeProvider _hcp;
|
|
|
|
static volatile IHashCodeProvider defaultHashProvider;
|
|
|
|
internal CompatibleComparer(IComparer comparer, IHashCodeProvider hashCodeProvider) {
|
|
_comparer = comparer;
|
|
_hcp = hashCodeProvider;
|
|
}
|
|
#pragma warning restore 618
|
|
|
|
public new bool Equals(Object a, Object b) {
|
|
if (a == b) return true;
|
|
if (a == null || b == null) return false;
|
|
|
|
// We must call Compare or CompareTo method
|
|
// to make sure everything is fine, but the
|
|
// guideline is that Equals should never throw.
|
|
// So we need to ignore ArgumentException (note this
|
|
// is the exception we should get if two objects are not
|
|
// comparable.)
|
|
|
|
try {
|
|
if (_comparer != null)
|
|
return (_comparer.Compare(a,b) == 0);
|
|
|
|
IComparable ia = a as IComparable;
|
|
if (ia != null)
|
|
return (ia.CompareTo(b) ==0);
|
|
}
|
|
catch(ArgumentException) {
|
|
return false;
|
|
}
|
|
|
|
return a.Equals(b);
|
|
}
|
|
|
|
public int GetHashCode(Object obj) {
|
|
if( obj == null) {
|
|
throw new ArgumentNullException("obj");
|
|
}
|
|
|
|
if (_hcp != null)
|
|
return _hcp.GetHashCode(obj);
|
|
return obj.GetHashCode();
|
|
}
|
|
|
|
public IComparer Comparer {
|
|
get {
|
|
return _comparer;
|
|
}
|
|
}
|
|
|
|
#pragma warning disable 618
|
|
public IHashCodeProvider HashCodeProvider {
|
|
get {
|
|
return _hcp;
|
|
}
|
|
}
|
|
#pragma warning restore 618
|
|
|
|
public static IComparer DefaultComparer {
|
|
get {
|
|
if( defaultComparer == null) {
|
|
defaultComparer = new CaseInsensitiveComparer(CultureInfo.InvariantCulture);
|
|
}
|
|
return defaultComparer;
|
|
}
|
|
}
|
|
|
|
#pragma warning disable 618
|
|
public static IHashCodeProvider DefaultHashCodeProvider {
|
|
get {
|
|
if( defaultHashProvider == null) {
|
|
defaultHashProvider = new CaseInsensitiveHashCodeProvider(CultureInfo.InvariantCulture);
|
|
}
|
|
return defaultHashProvider;
|
|
}
|
|
}
|
|
#pragma warning restore 618
|
|
}
|
|
}
|