1 //------------------------------------------------------------------------------ 2 // <copyright file="NameObjectCollectionBase.cs" company="Microsoft"> 3 // Copyright (c) Microsoft Corporation. All rights reserved. 4 // </copyright> 5 //------------------------------------------------------------------------------ 6 7 /* 8 * Ordered String/Object collection of name/value pairs with support for null key 9 * 10 * This class is intended to be used as a base class 11 * 12 * Copyright (c) 2000 Microsoft Corporation 13 */ 14 15 namespace System.Collections.Specialized { 16 17 using Microsoft.Win32; 18 using System.Collections; 19 using System.Diagnostics.CodeAnalysis; 20 using System.Globalization; 21 using System.Runtime.Serialization; 22 using System.Security.Permissions; 23 24 25 /// <devdoc> 26 /// <para>Provides the <see langword='abstract '/>base class for a sorted collection of associated <see cref='System.String' qualify='true'/> keys 27 /// and <see cref='System.Object' qualify='true'/> values that can be accessed either with the hash code of 28 /// the key or with the index.</para> 29 /// </devdoc> 30 [Serializable()] 31 public abstract class NameObjectCollectionBase : ICollection, ISerializable, IDeserializationCallback { 32 // const names used for serialization 33 private const String ReadOnlyName = "ReadOnly"; 34 private const String CountName = "Count"; 35 private const String ComparerName = "Comparer"; 36 private const String HashCodeProviderName = "HashProvider"; 37 private const String KeysName = "Keys"; 38 private const String ValuesName = "Values"; 39 private const String KeyComparerName = "KeyComparer"; 40 private const String VersionName = "Version"; 41 42 private bool _readOnly = false; 43 private ArrayList _entriesArray; 44 private IEqualityComparer _keyComparer; 45 private volatile Hashtable _entriesTable; 46 private volatile NameObjectEntry _nullKeyEntry; 47 private KeysCollection _keys; 48 private SerializationInfo _serializationInfo; 49 private int _version; 50 [NonSerialized] 51 private Object _syncRoot; 52 53 private static StringComparer defaultComparer = StringComparer.InvariantCultureIgnoreCase; 54 55 /// <devdoc> 56 /// <para> Creates an empty <see cref='System.Collections.Specialized.NameObjectCollectionBase'/> instance with the default initial capacity and using the default case-insensitive hash 57 /// code provider and the default case-insensitive comparer.</para> 58 /// </devdoc> NameObjectCollectionBase()59 protected NameObjectCollectionBase() :this(defaultComparer) { 60 } 61 NameObjectCollectionBase(IEqualityComparer equalityComparer)62 protected NameObjectCollectionBase(IEqualityComparer equalityComparer) 63 { 64 _keyComparer = (equalityComparer == null) ? defaultComparer : equalityComparer; 65 Reset(); 66 } 67 NameObjectCollectionBase(Int32 capacity, IEqualityComparer equalityComparer)68 protected NameObjectCollectionBase(Int32 capacity, IEqualityComparer equalityComparer) : this (equalityComparer) 69 { 70 Reset(capacity); 71 } 72 73 74 /// <devdoc> 75 /// <para>Creates an empty <see cref='System.Collections.Specialized.NameObjectCollectionBase'/> instance with 76 /// the default initial capacity and using the specified case-insensitive hash code provider and the 77 /// specified case-insensitive comparer.</para> 78 /// </devdoc> 79 80 #pragma warning disable 618 81 [Obsolete("Please use NameObjectCollectionBase(IEqualityComparer) instead.")] NameObjectCollectionBase(IHashCodeProvider hashProvider, IComparer comparer)82 protected NameObjectCollectionBase(IHashCodeProvider hashProvider, IComparer comparer) { 83 _keyComparer = new CompatibleComparer( comparer, hashProvider); 84 Reset(); 85 } 86 #pragma warning restore 618 87 88 /// <devdoc> 89 /// <para>Creates an empty <see cref='System.Collections.Specialized.NameObjectCollectionBase'/> instance with the specified 90 /// initial capacity and using the specified case-insensitive hash code provider 91 /// and the specified case-insensitive comparer.</para> 92 /// </devdoc> 93 #pragma warning disable 618 94 [Obsolete("Please use NameObjectCollectionBase(Int32, IEqualityComparer) instead.")] NameObjectCollectionBase(int capacity, IHashCodeProvider hashProvider, IComparer comparer)95 protected NameObjectCollectionBase(int capacity, IHashCodeProvider hashProvider, IComparer comparer) { 96 _keyComparer = new CompatibleComparer( comparer, hashProvider); 97 Reset(capacity); 98 } 99 #pragma warning restore 618 100 101 /// <devdoc> 102 /// <para>Creates an empty <see cref='System.Collections.Specialized.NameObjectCollectionBase'/> instance with the specified 103 /// initial capacity and using the default case-insensitive hash code provider 104 /// and the default case-insensitive comparer.</para> 105 /// </devdoc> NameObjectCollectionBase(int capacity)106 protected NameObjectCollectionBase(int capacity) { 107 _keyComparer = StringComparer.InvariantCultureIgnoreCase; 108 Reset(capacity); 109 } 110 111 // Allow internal extenders to avoid creating the hashtable/arraylist. NameObjectCollectionBase(DBNull dummy)112 internal NameObjectCollectionBase(DBNull dummy) 113 { 114 } 115 116 // 117 // Serialization support 118 // 119 120 /// <devdoc> 121 /// <para>[To be supplied.]</para> 122 /// </devdoc> NameObjectCollectionBase(SerializationInfo info, StreamingContext context)123 protected NameObjectCollectionBase(SerializationInfo info, StreamingContext context) { 124 _serializationInfo = info; 125 } 126 127 /// <devdoc> 128 /// <para>[To be supplied.]</para> 129 /// </devdoc> 130 [SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase", Justification = "System.dll is still using pre-v4 security model and needs this demand")] 131 [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.SerializationFormatter)] GetObjectData(SerializationInfo info, StreamingContext context)132 public virtual void GetObjectData(SerializationInfo info, StreamingContext context) { 133 if (info == null) 134 throw new ArgumentNullException("info"); 135 136 info.AddValue(ReadOnlyName, _readOnly); 137 138 #pragma warning disable 618 139 // Maintain backward serialization compatibility if new APIs are not used. 140 if( _keyComparer == defaultComparer) { 141 info.AddValue(HashCodeProviderName, CompatibleComparer.DefaultHashCodeProvider, typeof(IHashCodeProvider)); 142 info.AddValue(ComparerName, CompatibleComparer.DefaultComparer, typeof(IComparer)); 143 } 144 else if(_keyComparer == null) { 145 info.AddValue(HashCodeProviderName, null, typeof(IHashCodeProvider)); 146 info.AddValue(ComparerName, null, typeof(IComparer)); 147 } 148 else if(_keyComparer is CompatibleComparer) { 149 CompatibleComparer c = (CompatibleComparer)_keyComparer; 150 info.AddValue(HashCodeProviderName, c.HashCodeProvider, typeof(IHashCodeProvider)); 151 info.AddValue(ComparerName, c.Comparer, typeof(IComparer)); 152 } 153 else { 154 info.AddValue(KeyComparerName, _keyComparer, typeof(IEqualityComparer)); 155 } 156 #pragma warning restore 618 157 158 int count = _entriesArray.Count; 159 info.AddValue(CountName, count); 160 161 String[] keys = new String[count]; 162 Object[] values = new Object[count]; 163 164 for (int i = 0; i < count; i++) { 165 NameObjectEntry entry = (NameObjectEntry)_entriesArray[i]; 166 keys[i] = entry.Key; 167 values[i] = entry.Value; 168 } 169 170 info.AddValue(KeysName, keys, typeof(String[])); 171 info.AddValue(ValuesName, values, typeof(Object[])); 172 info.AddValue(VersionName, _version); 173 } 174 175 /// <devdoc> 176 /// <para>[To be supplied.]</para> 177 /// </devdoc> OnDeserialization(Object sender)178 public virtual void OnDeserialization(Object sender) { 179 if (_keyComparer != null) { 180 return;//Somebody had a dependency on this hashtable and fixed us up before the ObjectManager got to it. 181 } 182 183 if (_serializationInfo == null) 184 throw new SerializationException(); 185 186 SerializationInfo info = _serializationInfo; 187 _serializationInfo = null; 188 189 bool readOnly = false; 190 int count = 0; 191 String[] keys = null; 192 Object[] values = null; 193 #pragma warning disable 618 194 IHashCodeProvider hashProvider = null; 195 #pragma warning restore 618 196 IComparer comparer = null; 197 bool hasVersion = false; 198 int serializedVersion = 0; 199 200 SerializationInfoEnumerator enumerator = info.GetEnumerator(); 201 while( enumerator.MoveNext()) 202 { 203 switch( enumerator.Name) 204 { 205 case ReadOnlyName: 206 readOnly = info.GetBoolean(ReadOnlyName);; 207 break; 208 case HashCodeProviderName: 209 #pragma warning disable 618 210 hashProvider = (IHashCodeProvider)info.GetValue(HashCodeProviderName, typeof(IHashCodeProvider));; 211 #pragma warning restore 618 212 break; 213 case ComparerName: 214 comparer = (IComparer)info.GetValue(ComparerName, typeof(IComparer)); 215 break; 216 case KeyComparerName: 217 _keyComparer = (IEqualityComparer)info.GetValue(KeyComparerName, typeof(IEqualityComparer)); 218 break; 219 case CountName: 220 count = info.GetInt32(CountName); 221 break; 222 case KeysName: 223 keys = (String[])info.GetValue(KeysName, typeof(String[])); 224 break; 225 case ValuesName: 226 values = (Object[])info.GetValue(ValuesName, typeof(Object[])); 227 break; 228 case VersionName: 229 hasVersion = true; 230 serializedVersion = info.GetInt32(VersionName); 231 break; 232 } 233 } 234 235 if( _keyComparer == null) { 236 if(comparer == null || hashProvider == null) 237 { 238 throw new SerializationException(); 239 } 240 else { 241 // create a new key comparer for V1 Object 242 _keyComparer = new CompatibleComparer(comparer, hashProvider); 243 } 244 } 245 246 if ( keys == null || values == null) 247 throw new SerializationException(); 248 249 Reset(count); 250 251 for (int i = 0; i < count; i++) 252 BaseAdd(keys[i], values[i]); 253 254 _readOnly = readOnly; // after collection populated 255 if(hasVersion) { 256 _version = serializedVersion; 257 } 258 } 259 260 // 261 // Private helpers 262 // 263 Reset()264 private void Reset() { 265 _entriesArray = new ArrayList(); 266 _entriesTable = new Hashtable(_keyComparer); 267 _nullKeyEntry = null; 268 _version++; 269 } 270 Reset(int capacity)271 private void Reset(int capacity) { 272 _entriesArray = new ArrayList(capacity); 273 _entriesTable = new Hashtable(capacity, _keyComparer); 274 _nullKeyEntry = null; 275 _version++; 276 } 277 FindEntry(String key)278 private NameObjectEntry FindEntry(String key) { 279 if (key != null) 280 return (NameObjectEntry)_entriesTable[key]; 281 else 282 return _nullKeyEntry; 283 } 284 285 internal IEqualityComparer Comparer 286 { 287 get 288 { 289 return _keyComparer; 290 } 291 set 292 { 293 _keyComparer = value; 294 } 295 296 } 297 298 299 /// <devdoc> 300 /// <para>Gets or sets a value indicating whether the <see cref='System.Collections.Specialized.NameObjectCollectionBase'/> instance is read-only.</para> 301 /// </devdoc> 302 protected bool IsReadOnly { 303 get { return _readOnly; } 304 set { _readOnly = value; } 305 } 306 307 /// <devdoc> 308 /// <para>Gets a value indicating whether the <see cref='System.Collections.Specialized.NameObjectCollectionBase'/> instance contains entries whose 309 /// keys are not <see langword='null'/>.</para> 310 /// </devdoc> BaseHasKeys()311 protected bool BaseHasKeys() { 312 return (_entriesTable.Count > 0); // any entries with keys? 313 } 314 315 // 316 // Methods to add / remove entries 317 // 318 319 /// <devdoc> 320 /// <para>Adds an entry with the specified key and value into the 321 /// <see cref='System.Collections.Specialized.NameObjectCollectionBase'/> instance.</para> 322 /// </devdoc> BaseAdd(String name, Object value)323 protected void BaseAdd(String name, Object value) { 324 if (_readOnly) 325 throw new NotSupportedException(SR.GetString(SR.CollectionReadOnly)); 326 327 NameObjectEntry entry = new NameObjectEntry(name, value); 328 329 // insert entry into hashtable 330 if (name != null) { 331 if (_entriesTable[name] == null) 332 _entriesTable.Add(name, entry); 333 } 334 else { // null key -- special case -- hashtable doesn't like null keys 335 if (_nullKeyEntry == null) 336 _nullKeyEntry = entry; 337 } 338 339 // add entry to the list 340 _entriesArray.Add(entry); 341 342 _version++; 343 } 344 345 /// <devdoc> 346 /// <para>Removes the entries with the specified key from the 347 /// <see cref='System.Collections.Specialized.NameObjectCollectionBase'/> instance.</para> 348 /// </devdoc> BaseRemove(String name)349 protected void BaseRemove(String name) { 350 if (_readOnly) 351 throw new NotSupportedException(SR.GetString(SR.CollectionReadOnly)); 352 353 if (name != null) { 354 // remove from hashtable 355 _entriesTable.Remove(name); 356 357 // remove from array 358 for (int i = _entriesArray.Count-1; i >= 0; i--) { 359 if (_keyComparer.Equals(name, BaseGetKey(i))) 360 _entriesArray.RemoveAt(i); 361 } 362 } 363 else { // null key -- special case 364 // null out special 'null key' entry 365 _nullKeyEntry = null; 366 367 // remove from array 368 for (int i = _entriesArray.Count-1; i >= 0; i--) { 369 if (BaseGetKey(i) == null) 370 _entriesArray.RemoveAt(i); 371 } 372 } 373 374 _version++; 375 } 376 377 /// <devdoc> 378 /// <para> Removes the entry at the specified index of the 379 /// <see cref='System.Collections.Specialized.NameObjectCollectionBase'/> instance.</para> 380 /// </devdoc> BaseRemoveAt(int index)381 protected void BaseRemoveAt(int index) { 382 if (_readOnly) 383 throw new NotSupportedException(SR.GetString(SR.CollectionReadOnly)); 384 385 String key = BaseGetKey(index); 386 387 if (key != null) { 388 // remove from hashtable 389 _entriesTable.Remove(key); 390 } 391 else { // null key -- special case 392 // null out special 'null key' entry 393 _nullKeyEntry = null; 394 } 395 396 // remove from array 397 _entriesArray.RemoveAt(index); 398 399 _version++; 400 } 401 402 /// <devdoc> 403 /// <para>Removes all entries from the <see cref='System.Collections.Specialized.NameObjectCollectionBase'/> instance.</para> 404 /// </devdoc> BaseClear()405 protected void BaseClear() { 406 if (_readOnly) 407 throw new NotSupportedException(SR.GetString(SR.CollectionReadOnly)); 408 409 Reset(); 410 } 411 412 // 413 // Access by name 414 // 415 416 /// <devdoc> 417 /// <para>Gets the value of the first entry with the specified key from 418 /// the <see cref='System.Collections.Specialized.NameObjectCollectionBase'/> instance.</para> 419 /// </devdoc> BaseGet(String name)420 protected Object BaseGet(String name) { 421 NameObjectEntry e = FindEntry(name); 422 return (e != null) ? e.Value : null; 423 } 424 425 /// <devdoc> 426 /// <para>Sets the value of the first entry with the specified key in the <see cref='System.Collections.Specialized.NameObjectCollectionBase'/> 427 /// instance, if found; otherwise, adds an entry with the specified key and value 428 /// into the <see cref='System.Collections.Specialized.NameObjectCollectionBase'/> 429 /// instance.</para> 430 /// </devdoc> BaseSet(String name, Object value)431 protected void BaseSet(String name, Object value) { 432 if (_readOnly) 433 throw new NotSupportedException(SR.GetString(SR.CollectionReadOnly)); 434 435 NameObjectEntry entry = FindEntry(name); 436 if (entry != null) { 437 entry.Value = value; 438 _version++; 439 } 440 else { 441 BaseAdd(name, value); 442 } 443 } 444 445 // 446 // Access by index 447 // 448 449 /// <devdoc> 450 /// <para>Gets the value of the entry at the specified index of 451 /// the <see cref='System.Collections.Specialized.NameObjectCollectionBase'/> instance.</para> 452 /// </devdoc> BaseGet(int index)453 protected Object BaseGet(int index) { 454 NameObjectEntry entry = (NameObjectEntry)_entriesArray[index]; 455 return entry.Value; 456 } 457 458 /// <devdoc> 459 /// <para>Gets the key of the entry at the specified index of the 460 /// <see cref='System.Collections.Specialized.NameObjectCollectionBase'/> 461 /// instance.</para> 462 /// </devdoc> BaseGetKey(int index)463 protected String BaseGetKey(int index) { 464 NameObjectEntry entry = (NameObjectEntry)_entriesArray[index]; 465 return entry.Key; 466 } 467 468 /// <devdoc> 469 /// <para>Sets the value of the entry at the specified index of 470 /// the <see cref='System.Collections.Specialized.NameObjectCollectionBase'/> instance.</para> 471 /// </devdoc> BaseSet(int index, Object value)472 protected void BaseSet(int index, Object value) { 473 if (_readOnly) 474 throw new NotSupportedException(SR.GetString(SR.CollectionReadOnly)); 475 476 NameObjectEntry entry = (NameObjectEntry)_entriesArray[index]; 477 entry.Value = value; 478 _version++; 479 } 480 481 // 482 // ICollection implementation 483 // 484 485 /// <devdoc> 486 /// <para>Returns an enumerator that can iterate through the <see cref='System.Collections.Specialized.NameObjectCollectionBase'/>.</para> 487 /// </devdoc> GetEnumerator()488 public virtual IEnumerator GetEnumerator() { 489 return new NameObjectKeysEnumerator(this); 490 } 491 492 /// <devdoc> 493 /// <para>Gets the number of key-and-value pairs in the <see cref='System.Collections.Specialized.NameObjectCollectionBase'/> instance.</para> 494 /// </devdoc> 495 public virtual int Count { 496 get { 497 return _entriesArray.Count; 498 } 499 } 500 ICollection.CopyTo(Array array, int index)501 void ICollection.CopyTo(Array array, int index) { 502 if (array==null) { 503 throw new ArgumentNullException("array"); 504 } 505 506 if (array.Rank != 1) { 507 throw new ArgumentException(SR.GetString(SR.Arg_MultiRank)); 508 } 509 510 if (index < 0) { 511 throw new ArgumentOutOfRangeException("index",SR.GetString(SR.IndexOutOfRange, index.ToString(CultureInfo.CurrentCulture)) ); 512 } 513 514 if (array.Length - index < _entriesArray.Count) { 515 throw new ArgumentException(SR.GetString(SR.Arg_InsufficientSpace)); 516 } 517 518 for (IEnumerator e = this.GetEnumerator(); e.MoveNext();) 519 array.SetValue(e.Current, index++); 520 } 521 522 Object ICollection.SyncRoot { 523 get { 524 if( _syncRoot == null) { 525 System.Threading.Interlocked.CompareExchange(ref _syncRoot, new Object(), null); 526 } 527 return _syncRoot; 528 } 529 } 530 531 bool ICollection.IsSynchronized { 532 get { return false; } 533 } 534 535 // 536 // Helper methods to get arrays of keys and values 537 // 538 539 /// <devdoc> 540 /// <para>Returns a <see cref='System.String' qualify='true'/> array containing all the keys in the 541 /// <see cref='System.Collections.Specialized.NameObjectCollectionBase'/> instance.</para> 542 /// </devdoc> BaseGetAllKeys()543 protected String[] BaseGetAllKeys() { 544 int n = _entriesArray.Count; 545 String[] allKeys = new String[n]; 546 547 for (int i = 0; i < n; i++) 548 allKeys[i] = BaseGetKey(i); 549 550 return allKeys; 551 } 552 553 /// <devdoc> 554 /// <para>Returns an <see cref='System.Object' qualify='true'/> array containing all the values in the 555 /// <see cref='System.Collections.Specialized.NameObjectCollectionBase'/> instance.</para> 556 /// </devdoc> BaseGetAllValues()557 protected Object[] BaseGetAllValues() { 558 int n = _entriesArray.Count; 559 Object[] allValues = new Object[n]; 560 561 for (int i = 0; i < n; i++) 562 allValues[i] = BaseGet(i); 563 564 return allValues; 565 } 566 567 /// <devdoc> 568 /// <para>Returns an array of the specified type containing 569 /// all the values in the <see cref='System.Collections.Specialized.NameObjectCollectionBase'/> instance.</para> 570 /// </devdoc> BaseGetAllValues(Type type)571 protected object[] BaseGetAllValues(Type type) { 572 int n = _entriesArray.Count; 573 if (type == null) { 574 throw new ArgumentNullException("type"); 575 } 576 object[] allValues = (object[]) SecurityUtils.ArrayCreateInstance(type, n); 577 578 for (int i = 0; i < n; i++) { 579 allValues[i] = BaseGet(i); 580 } 581 582 return allValues; 583 } 584 585 // 586 // Keys propetry 587 // 588 589 /// <devdoc> 590 /// <para>Returns a <see cref='System.Collections.Specialized.NameObjectCollectionBase.KeysCollection'/> instance containing 591 /// all the keys in the <see cref='System.Collections.Specialized.NameObjectCollectionBase'/> instance.</para> 592 /// </devdoc> 593 public virtual KeysCollection Keys { 594 get { 595 if (_keys == null) 596 _keys = new KeysCollection(this); 597 return _keys; 598 } 599 } 600 601 // 602 // Simple entry class to allow substitution of values and indexed access to keys 603 // 604 605 internal class NameObjectEntry { 606 NameObjectEntry(String name, Object value)607 internal NameObjectEntry(String name, Object value) { 608 Key = name; 609 Value = value; 610 } 611 612 internal String Key; 613 internal Object Value; 614 } 615 616 // 617 // Enumerator over keys of NameObjectCollection 618 // 619 620 [Serializable()] 621 internal class NameObjectKeysEnumerator : IEnumerator { 622 private int _pos; 623 private NameObjectCollectionBase _coll; 624 private int _version; 625 NameObjectKeysEnumerator(NameObjectCollectionBase coll)626 internal NameObjectKeysEnumerator(NameObjectCollectionBase coll) { 627 _coll = coll; 628 _version = _coll._version; 629 _pos = -1; 630 } 631 MoveNext()632 public bool MoveNext() { 633 if ( _version != _coll._version) 634 throw new InvalidOperationException(SR.GetString(SR.InvalidOperation_EnumFailedVersion)); 635 636 if( _pos < _coll.Count - 1) { 637 _pos++; 638 return true; 639 } 640 else { 641 _pos = _coll.Count; 642 return false; 643 } 644 645 } 646 Reset()647 public void Reset() { 648 if (_version != _coll._version) 649 throw new InvalidOperationException(SR.GetString(SR.InvalidOperation_EnumFailedVersion)); 650 _pos = -1; 651 } 652 653 public Object Current { 654 get { 655 if(_pos >= 0 && _pos < _coll.Count) { 656 return _coll.BaseGetKey(_pos); 657 } 658 else { 659 throw new InvalidOperationException(SR.GetString(SR.InvalidOperation_EnumOpCantHappen)); 660 } 661 } 662 } 663 } 664 665 // 666 // Keys collection 667 // 668 669 /// <devdoc> 670 /// <para>Represents a collection of the <see cref='System.String' qualify='true'/> keys of a collection.</para> 671 /// </devdoc> 672 [Serializable()] 673 public class KeysCollection : ICollection { 674 675 private NameObjectCollectionBase _coll; 676 KeysCollection(NameObjectCollectionBase coll)677 internal KeysCollection(NameObjectCollectionBase coll) { 678 _coll = coll; 679 } 680 681 // Indexed access 682 683 /// <devdoc> 684 /// <para> Gets the key at the specified index of the collection.</para> 685 /// </devdoc> Get(int index)686 public virtual String Get(int index) { 687 return _coll.BaseGetKey(index); 688 } 689 690 /// <devdoc> 691 /// <para>Represents the entry at the specified index of the collection.</para> 692 /// </devdoc> 693 public String this[int index] { 694 get { 695 return Get(index); 696 } 697 } 698 699 // ICollection implementation 700 701 /// <devdoc> 702 /// <para>Returns an enumerator that can iterate through the 703 /// <see cref='System.Collections.Specialized.NameObjectCollectionBase.KeysCollection'/>.</para> 704 /// </devdoc> GetEnumerator()705 public IEnumerator GetEnumerator() { 706 return new NameObjectKeysEnumerator(_coll); 707 } 708 709 /// <devdoc> 710 /// <para>Gets the number of keys in the <see cref='System.Collections.Specialized.NameObjectCollectionBase.KeysCollection'/>.</para> 711 /// </devdoc> 712 public int Count { 713 get { 714 return _coll.Count; 715 } 716 } 717 ICollection.CopyTo(Array array, int index)718 void ICollection.CopyTo(Array array, int index) { 719 if (array==null) { 720 throw new ArgumentNullException("array"); 721 } 722 723 if (array.Rank != 1) { 724 throw new ArgumentException(SR.GetString(SR.Arg_MultiRank)); 725 } 726 727 if (index < 0) { 728 throw new ArgumentOutOfRangeException("index",SR.GetString(SR.IndexOutOfRange, index.ToString(CultureInfo.CurrentCulture)) ); 729 } 730 731 if (array.Length - index < _coll.Count) { 732 throw new ArgumentException(SR.GetString(SR.Arg_InsufficientSpace)); 733 } 734 735 for (IEnumerator e = this.GetEnumerator(); e.MoveNext();) 736 array.SetValue(e.Current, index++); 737 } 738 739 Object ICollection.SyncRoot { 740 get { return ((ICollection)_coll).SyncRoot; } 741 } 742 743 744 bool ICollection.IsSynchronized { 745 get { return false; } 746 } 747 } 748 } 749 750 [Serializable()] 751 internal class CompatibleComparer: IEqualityComparer { 752 IComparer _comparer; 753 static volatile IComparer defaultComparer; 754 // Needed for compatability 755 #pragma warning disable 618 756 IHashCodeProvider _hcp; 757 758 static volatile IHashCodeProvider defaultHashProvider; 759 CompatibleComparer(IComparer comparer, IHashCodeProvider hashCodeProvider)760 internal CompatibleComparer(IComparer comparer, IHashCodeProvider hashCodeProvider) { 761 _comparer = comparer; 762 _hcp = hashCodeProvider; 763 } 764 #pragma warning restore 618 765 Equals(Object a, Object b)766 public new bool Equals(Object a, Object b) { 767 if (a == b) return true; 768 if (a == null || b == null) return false; 769 770 // We must call Compare or CompareTo method 771 // to make sure everything is fine, but the 772 // guideline is that Equals should never throw. 773 // So we need to ignore ArgumentException (note this 774 // is the exception we should get if two objects are not 775 // comparable.) 776 777 try { 778 if (_comparer != null) 779 return (_comparer.Compare(a,b) == 0); 780 781 IComparable ia = a as IComparable; 782 if (ia != null) 783 return (ia.CompareTo(b) ==0); 784 } 785 catch(ArgumentException) { 786 return false; 787 } 788 789 return a.Equals(b); 790 } 791 GetHashCode(Object obj)792 public int GetHashCode(Object obj) { 793 if( obj == null) { 794 throw new ArgumentNullException("obj"); 795 } 796 797 if (_hcp != null) 798 return _hcp.GetHashCode(obj); 799 return obj.GetHashCode(); 800 } 801 802 public IComparer Comparer { 803 get { 804 return _comparer; 805 } 806 } 807 808 #pragma warning disable 618 809 public IHashCodeProvider HashCodeProvider { 810 get { 811 return _hcp; 812 } 813 } 814 #pragma warning restore 618 815 816 public static IComparer DefaultComparer { 817 get { 818 if( defaultComparer == null) { 819 defaultComparer = new CaseInsensitiveComparer(CultureInfo.InvariantCulture); 820 } 821 return defaultComparer; 822 } 823 } 824 825 #pragma warning disable 618 826 public static IHashCodeProvider DefaultHashCodeProvider { 827 get { 828 if( defaultHashProvider == null) { 829 defaultHashProvider = new CaseInsensitiveHashCodeProvider(CultureInfo.InvariantCulture); 830 } 831 return defaultHashProvider; 832 } 833 } 834 #pragma warning restore 618 835 } 836 } 837