2 // System.Collections.Hashtable.cs
5 // Sergey Chaban (serge@wildwestsoftware.com)
9 // Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 using System
.Collections
;
33 using System
.Runtime
.Serialization
;
35 using System
.Runtime
.ConstrainedExecution
;
36 using System
.Runtime
.InteropServices
;
37 using System
.Diagnostics
;
39 namespace System
.Collections
{
42 [DebuggerDisplay ("Count={Count}")]
43 [DebuggerTypeProxy (typeof (CollectionDebuggerView
))]
50 class Hashtable
: IDictionary
, ICollection
,
51 IEnumerable
, ICloneable
, ISerializable
, IDeserializationCallback
55 internal struct Slot
{
58 internal Object
value;
62 internal class KeyMarker
67 public readonly static KeyMarker Removed
= new KeyMarker();
69 public object GetRealObject (StreamingContext context
)
71 return KeyMarker
.Removed
;
80 const int CHAIN_MARKER
= ~Int32
.MaxValue
;
84 private int modificationCount
;
85 private float loadFactor
;
86 private Slot
[] table
;
87 // Hashcodes of the corresponding entries in the slot table. Kept separate to
89 private int [] hashes
;
91 private int threshold
;
93 private HashKeys hashKeys
;
94 private HashValues hashValues
;
96 private IHashCodeProvider hcpRef
;
97 private IComparer comparerRef
;
98 private SerializationInfo serializationInfo
;
100 private IEqualityComparer equalityComparer
;
102 private static readonly int [] primeTbl
= {
143 public Hashtable () : this (0, 1.0f
) {}
145 [Obsolete ("Please use Hashtable(int, float, IEqualityComparer) instead")]
146 public Hashtable (int capacity
, float loadFactor
, IHashCodeProvider hcp
, IComparer comparer
) {
148 throw new ArgumentOutOfRangeException ("capacity", "negative capacity");
150 if (loadFactor
< 0.1f
|| loadFactor
> 1.0f
|| Single
.IsNaN (loadFactor
))
151 throw new ArgumentOutOfRangeException ("loadFactor", "load factor");
153 if (capacity
== 0) ++capacity
;
154 this.loadFactor
= 0.75f
*loadFactor
;
155 double tableSize
= capacity
/ this.loadFactor
;
157 if (tableSize
> Int32
.MaxValue
)
158 throw new ArgumentException ("Size is too big");
160 int size
= (int) tableSize
;
161 size
= ToPrime (size
);
162 this.SetTable (new Slot
[size
], new int [size
]);
165 this.comparer
= comparer
;
168 this.modificationCount
= 0;
171 public Hashtable (int capacity
, float loadFactor
) :
172 this (capacity
, loadFactor
, null, null)
176 public Hashtable (int capacity
) : this (capacity
, 1.0f
)
181 // Used as a faster Clone
183 internal Hashtable (Hashtable source
)
185 inUse
= source
.inUse
;
186 loadFactor
= source
.loadFactor
;
188 table
= (Slot
[]) source
.table
.Clone ();
189 hashes
= (int []) source
.hashes
.Clone ();
190 threshold
= source
.threshold
;
191 hcpRef
= source
.hcpRef
;
192 comparerRef
= source
.comparerRef
;
193 equalityComparer
= source
.equalityComparer
;
196 [Obsolete ("Please use Hashtable(int, IEqualityComparer) instead")]
197 public Hashtable (int capacity
,
198 IHashCodeProvider hcp
,
200 : this (capacity
, 1.0f
, hcp
, comparer
)
204 [Obsolete ("Please use Hashtable(IDictionary, float, IEqualityComparer) instead")]
205 public Hashtable (IDictionary d
, float loadFactor
,
206 IHashCodeProvider hcp
, IComparer comparer
)
207 : this (d
!=null ? d
.Count
: 0,
208 loadFactor
, hcp
, comparer
)
212 throw new ArgumentNullException ("dictionary");
214 IDictionaryEnumerator it
= d
.GetEnumerator ();
215 while (it
.MoveNext ()) {
216 Add (it
.Key
, it
.Value
);
221 public Hashtable (IDictionary d
, float loadFactor
)
222 : this (d
, loadFactor
, null, null)
227 public Hashtable (IDictionary d
) : this (d
, 1.0f
)
231 [Obsolete ("Please use Hashtable(IDictionary, IEqualityComparer) instead")]
232 public Hashtable (IDictionary d
, IHashCodeProvider hcp
, IComparer comparer
)
233 : this (d
, 1.0f
, hcp
, comparer
)
237 [Obsolete ("Please use Hashtable(IEqualityComparer) instead")]
238 public Hashtable (IHashCodeProvider hcp
, IComparer comparer
)
239 : this (1, 1.0f
, hcp
, comparer
)
243 protected Hashtable (SerializationInfo info
, StreamingContext context
)
245 serializationInfo
= info
;
248 public Hashtable (IDictionary d
, IEqualityComparer equalityComparer
) : this (d
, 1.0f
, equalityComparer
)
252 public Hashtable (IDictionary d
, float loadFactor
, IEqualityComparer equalityComparer
) : this (d
, loadFactor
)
254 this.equalityComparer
= equalityComparer
;
257 public Hashtable (IEqualityComparer equalityComparer
) : this (1, 1.0f
, equalityComparer
)
261 public Hashtable (int capacity
, IEqualityComparer equalityComparer
) : this (capacity
, 1.0f
, equalityComparer
)
265 public Hashtable (int capacity
, float loadFactor
, IEqualityComparer equalityComparer
) : this (capacity
, loadFactor
)
267 this.equalityComparer
= equalityComparer
;
274 [Obsolete ("Please use EqualityComparer property.")]
275 protected IComparer comparer
{
284 [Obsolete ("Please use EqualityComparer property.")]
285 protected IHashCodeProvider hcp
{
294 protected IEqualityComparer EqualityComparer
{
296 return equalityComparer
;
302 public virtual int Count
{
308 public virtual bool IsSynchronized
{
314 public virtual Object SyncRoot
{
324 public virtual bool IsFixedSize
{
331 public virtual bool IsReadOnly
{
337 public virtual ICollection Keys
{
339 if (this.hashKeys
== null)
340 this.hashKeys
= new HashKeys (this);
341 return this.hashKeys
;
345 public virtual ICollection Values
{
347 if (this.hashValues
== null)
348 this.hashValues
= new HashValues (this);
349 return this.hashValues
;
355 public virtual Object
this [Object key
] {
358 throw new ArgumentNullException ("key", "null key");
360 Slot
[] table
= this.table
;
361 int [] hashes
= this.hashes
;
362 uint size
= (uint) table
.Length
;
363 int h
= this.GetHash (key
) & Int32
.MaxValue
;
365 uint step
= (uint) ((h
>> 5)+1) % (size
-1)+1;
368 for (uint i
= size
; i
> 0; i
--) {
370 Slot entry
= table
[indx
];
371 int hashMix
= hashes
[indx
];
372 Object k
= entry
.key
;
376 if (k
== key
|| ((hashMix
& Int32
.MaxValue
) == h
377 && this.KeyEquals (key
, k
))) {
381 if ((hashMix
& CHAIN_MARKER
) == 0)
391 PutImpl (key
, value, true);
405 IEnumerator IEnumerable
.GetEnumerator ()
407 return new Enumerator (this, EnumeratorMode
.ENTRY_MODE
);
412 public virtual void CopyTo (Array array
, int arrayIndex
)
415 throw new ArgumentNullException ("array");
418 throw new ArgumentOutOfRangeException ("arrayIndex");
421 throw new ArgumentException ("array is multidimensional");
423 if ((array
.Length
> 0) && (arrayIndex
>= array
.Length
))
424 throw new ArgumentException ("arrayIndex is equal to or greater than array.Length");
426 if (arrayIndex
+ this.inUse
> array
.Length
)
427 throw new ArgumentException ("Not enough room from arrayIndex to end of array for this Hashtable");
429 IDictionaryEnumerator it
= GetEnumerator ();
432 while (it
.MoveNext ()) {
433 array
.SetValue (it
.Entry
, i
++);
440 public virtual void Add (Object key
, Object
value)
442 PutImpl (key
, value, false);
445 [ReliabilityContractAttribute (Consistency
.WillNotCorruptState
, Cer
.Success
)]
446 public virtual void Clear ()
448 for (int i
= 0;i
<table
.Length
;i
++) {
449 table
[i
].key
= null;
450 table
[i
].value = null;
458 public virtual bool Contains (Object key
)
460 return (Find (key
) >= 0);
463 public virtual IDictionaryEnumerator
GetEnumerator ()
465 return new Enumerator (this, EnumeratorMode
.ENTRY_MODE
);
468 [ReliabilityContractAttribute (Consistency
.WillNotCorruptState
, Cer
.MayFail
)]
469 public virtual void Remove (Object key
)
473 Slot
[] table
= this.table
;
477 table
[i
].key
= (h
!= 0)
480 table
[i
].value = null;
486 public virtual bool ContainsKey (object key
)
488 return Contains (key
);
491 public virtual bool ContainsValue (object value)
493 int size
= this.table
.Length
;
494 Slot
[] table
= this.table
;
496 for (int i
= 0; i
< size
; i
++) {
497 Slot entry
= table
[i
];
498 if (entry
.key
!= null && entry
.key
!= KeyMarker
.Removed
499 && entry
.value == null) {
504 for (int i
= 0; i
< size
; i
++) {
505 Slot entry
= table
[i
];
506 if (entry
.key
!= null && entry
.key
!= KeyMarker
.Removed
507 && value.Equals (entry
.value)) {
518 public virtual object Clone ()
520 return new Hashtable (this);
523 public virtual void GetObjectData (SerializationInfo info
, StreamingContext context
)
526 throw new ArgumentNullException ("info");
528 info
.AddValue ("LoadFactor", loadFactor
);
529 info
.AddValue ("Version", modificationCount
);
530 if (equalityComparer
!= null)
531 info
.AddValue ("KeyComparer", equalityComparer
);
533 info
.AddValue ("Comparer", comparerRef
);
535 info
.AddValue ("HashCodeProvider", hcpRef
);
536 info
.AddValue ("HashSize", this.table
.Length
);
538 Object
[] keys
= new Object
[inUse
];
539 CopyToArray(keys
, 0, EnumeratorMode
.KEY_MODE
);
542 Object
[] values
= new Object
[inUse
];
543 CopyToArray(values
, 0, EnumeratorMode
.VALUE_MODE
);
545 info
.AddValue ("Keys", keys
);
546 info
.AddValue ("Values", values
);
548 info
.AddValue ("equalityComparer", equalityComparer
);
551 [MonoTODO ("Serialize equalityComparer")]
552 public virtual void OnDeserialization (object sender
)
554 if (serializationInfo
== null) return;
556 loadFactor
= (float) serializationInfo
.GetValue ("LoadFactor", typeof(float));
557 modificationCount
= (int) serializationInfo
.GetValue ("Version", typeof(int));
559 equalityComparer
= (IEqualityComparer
) serializationInfo
.GetValue ("KeyComparer", typeof (object));
561 // If not found, try to get "Comparer"
564 if (equalityComparer
== null)
565 comparerRef
= (IComparer
) serializationInfo
.GetValue ("Comparer", typeof (object));
567 hcpRef
= (IHashCodeProvider
) serializationInfo
.GetValue ("HashCodeProvider", typeof (object));
568 } catch {} // Missing value => null
569 int size
= (int) serializationInfo
.GetValue ("HashSize", typeof(int));
571 Object
[] keys
= (Object
[]) serializationInfo
.GetValue("Keys", typeof(Object
[] ));
572 Object
[] values
= (Object
[]) serializationInfo
.GetValue("Values", typeof(Object
[] ));
574 if (keys
.Length
!= values
.Length
)
575 throw new SerializationException("Keys and values of uneven size");
577 size
= ToPrime (size
);
578 this.SetTable (new Slot
[size
], new int [size
]);
580 for(int i
=0;i
<keys
.Length
;i
++)
581 Add(keys
[i
], values
[i
]);
585 serializationInfo
= null;
589 /// Returns a synchronized (thread-safe)
590 /// wrapper for the Hashtable.
592 public static Hashtable
Synchronized (Hashtable table
)
595 throw new ArgumentNullException("table");
596 return new SyncHashtable (table
);
602 // Protected instance methods
605 /// <summary>Returns the hash code for the specified key.</summary>
606 protected virtual int GetHash (Object key
)
608 if (equalityComparer
!= null)
609 return equalityComparer
.GetHashCode (key
);
611 return key
.GetHashCode ();
613 return hcpRef
.GetHashCode (key
);
617 /// Compares a specific Object with a specific key
618 /// in the Hashtable.
620 protected virtual bool KeyEquals (Object item
, Object key
)
622 if (key
== KeyMarker
.Removed
)
624 if (equalityComparer
!= null)
625 return equalityComparer
.Equals (item
, key
);
626 if (comparerRef
== null)
627 return item
.Equals (key
);
629 return comparerRef
.Compare (item
, key
) == 0;
635 // Private instance methods
638 private void AdjustThreshold ()
640 int size
= table
.Length
;
642 threshold
= (int) (size
*loadFactor
);
643 if (this.threshold
>= size
)
647 private void SetTable (Slot
[] table
, int[] hashes
)
650 throw new ArgumentNullException ("table");
653 this.hashes
= hashes
;
657 private int Find (Object key
)
660 throw new ArgumentNullException ("key", "null key");
662 Slot
[] table
= this.table
;
663 int [] hashes
= this.hashes
;
664 uint size
= (uint) table
.Length
;
665 int h
= this.GetHash (key
) & Int32
.MaxValue
;
667 uint step
= (uint) ((h
>> 5)+1) % (size
-1)+1;
670 for (uint i
= size
; i
> 0; i
--) {
672 Slot entry
= table
[indx
];
673 int hashMix
= hashes
[indx
];
674 Object k
= entry
.key
;
678 if (k
== key
|| ((hashMix
& Int32
.MaxValue
) == h
679 && this.KeyEquals (key
, k
))) {
683 if ((hashMix
& CHAIN_MARKER
) == 0)
692 private void Rehash ()
694 int oldSize
= this.table
.Length
;
696 // From the SDK docs:
697 // Hashtable is automatically increased
698 // to the smallest prime number that is larger
699 // than twice the current number of Hashtable buckets
700 uint newSize
= (uint)ToPrime ((oldSize
<<1)|1);
703 Slot
[] newTable
= new Slot
[newSize
];
704 Slot
[] table
= this.table
;
705 int [] newHashes
= new int [newSize
];
706 int [] hashes
= this.hashes
;
708 for (int i
= 0;i
<oldSize
;i
++) {
711 int h
= hashes
[i
] & Int32
.MaxValue
;
713 uint step
= ((uint) (h
>>5)+1)% (newSize
-1)+1;
714 for (uint j
= spot
%newSize
;;spot
+= step
, j
= spot
%newSize
) {
715 // No check for KeyMarker.Removed here,
716 // because the table is just allocated.
717 if (newTable
[j
].key
== null) {
718 newTable
[j
].key
= s
.key
;
719 newTable
[j
].value = s
.value;
723 newHashes
[j
] |= CHAIN_MARKER
;
729 ++this.modificationCount
;
731 this.SetTable (newTable
, newHashes
);
735 private void PutImpl (Object key
, Object
value, bool overwrite
)
738 throw new ArgumentNullException ("key", "null key");
740 if (this.inUse
>= this.threshold
)
743 uint size
= (uint)this.table
.Length
;
745 int h
= this.GetHash (key
) & Int32
.MaxValue
;
747 uint step
= (uint) ((spot
>>5)+1)% (size
-1)+1;
748 Slot
[] table
= this.table
;
749 int [] hashes
= this.hashes
;
753 for (int i
= 0; i
< size
; i
++) {
754 int indx
= (int) (spot
% size
);
755 entry
= table
[indx
];
756 int hashMix
= hashes
[indx
];
759 && entry
.key
== KeyMarker
.Removed
760 && (hashMix
& CHAIN_MARKER
) != 0)
763 if (entry
.key
== null ||
764 (entry
.key
== KeyMarker
.Removed
765 && (hashMix
& CHAIN_MARKER
) == 0)) {
772 if ((hashMix
& Int32
.MaxValue
) == h
&& KeyEquals (key
, entry
.key
)) {
774 table
[indx
].value = value;
775 ++this.modificationCount
;
778 // An entry with the same key already exists in the Hashtable.
779 throw new ArgumentException (
780 "Key duplication when adding: " + key
);
785 if (freeIndx
== -1) {
786 hashes
[indx
] |= CHAIN_MARKER
;
794 table
[freeIndx
].key
= key
;
795 table
[freeIndx
].value = value;
796 hashes
[freeIndx
] |= h
;
799 ++this.modificationCount
;
804 private void CopyToArray (Array arr
, int i
,
807 IEnumerator it
= new Enumerator (this, mode
);
809 while (it
.MoveNext ()) {
810 arr
.SetValue (it
.Current
, i
++);
817 // Private static methods
819 internal static bool TestPrime (int x
)
822 int top
= (int)Math
.Sqrt (x
);
824 for (int n
= 3; n
< top
; n
+= 2) {
830 // There is only one even prime - 2.
834 internal static int CalcPrime (int x
)
836 for (int i
= (x
& (~
1))-1; i
< Int32
.MaxValue
; i
+= 2) {
837 if (TestPrime (i
)) return i
;
842 internal static int ToPrime (int x
)
844 for (int i
= 0; i
< primeTbl
.Length
; i
++) {
845 if (x
<= primeTbl
[i
])
848 return CalcPrime (x
);
858 private enum EnumeratorMode
: int {KEY_MODE = 0, VALUE_MODE, ENTRY_MODE}
;
861 private sealed class Enumerator
: IDictionaryEnumerator
, IEnumerator
{
863 private Hashtable host
;
867 private EnumeratorMode mode
;
869 private Object currentKey
;
870 private Object currentValue
;
872 private readonly static string xstr
= "Hashtable.Enumerator: snapshot out of sync.";
874 public Enumerator (Hashtable host
, EnumeratorMode mode
) {
876 stamp
= host
.modificationCount
;
877 size
= host
.table
.Length
;
882 public Enumerator (Hashtable host
)
883 : this (host
, EnumeratorMode
.KEY_MODE
) {}
886 private void FailFast ()
888 if (host
.modificationCount
!= stamp
) {
889 throw new InvalidOperationException (xstr
);
902 public bool MoveNext ()
907 while (++pos
< size
) {
908 Slot entry
= host
.table
[pos
];
910 if (entry
.key
!= null && entry
.key
!= KeyMarker
.Removed
) {
911 currentKey
= entry
.key
;
912 currentValue
= entry
.value;
923 public DictionaryEntry Entry
926 if (currentKey
== null) throw new InvalidOperationException ();
928 return new DictionaryEntry (currentKey
, currentValue
);
934 if (currentKey
== null) throw new InvalidOperationException ();
940 public Object Value
{
942 if (currentKey
== null) throw new InvalidOperationException ();
948 public Object Current
{
950 if (currentKey
== null) throw new InvalidOperationException ();
953 case EnumeratorMode
.KEY_MODE
:
955 case EnumeratorMode
.VALUE_MODE
:
957 case EnumeratorMode
.ENTRY_MODE
:
958 return new DictionaryEntry (currentKey
, currentValue
);
960 throw new Exception ("should never happen");
966 [DebuggerDisplay ("Count={Count}")]
967 [DebuggerTypeProxy (typeof (CollectionDebuggerView
))]
968 private class HashKeys
: ICollection
, IEnumerable
{
970 private Hashtable host
;
972 public HashKeys (Hashtable host
) {
974 throw new ArgumentNullException ();
981 public virtual int Count
{
987 public virtual bool IsSynchronized
{
989 return host
.IsSynchronized
;
993 public virtual Object SyncRoot
{
994 get {return host.SyncRoot;}
997 public virtual void CopyTo (Array array
, int arrayIndex
)
1000 throw new ArgumentNullException ("array");
1001 if (array
.Rank
!= 1)
1002 throw new ArgumentException ("array");
1004 throw new ArgumentOutOfRangeException ("arrayIndex");
1005 if (array
.Length
- arrayIndex
< Count
)
1006 throw new ArgumentException ("not enough space");
1008 host
.CopyToArray (array
, arrayIndex
, EnumeratorMode
.KEY_MODE
);
1013 public virtual IEnumerator
GetEnumerator ()
1015 return new Hashtable
.Enumerator (host
, EnumeratorMode
.KEY_MODE
);
1020 [DebuggerDisplay ("Count={Count}")]
1021 [DebuggerTypeProxy (typeof (CollectionDebuggerView
))]
1022 private class HashValues
: ICollection
, IEnumerable
{
1024 private Hashtable host
;
1026 public HashValues (Hashtable host
) {
1028 throw new ArgumentNullException ();
1035 public virtual int Count
{
1041 public virtual bool IsSynchronized
{
1043 return host
.IsSynchronized
;
1047 public virtual Object SyncRoot
{
1049 return host
.SyncRoot
;
1053 public virtual void CopyTo (Array array
, int arrayIndex
)
1056 throw new ArgumentNullException ("array");
1057 if (array
.Rank
!= 1)
1058 throw new ArgumentException ("array");
1060 throw new ArgumentOutOfRangeException ("arrayIndex");
1061 if (array
.Length
- arrayIndex
< Count
)
1062 throw new ArgumentException ("not enough space");
1064 host
.CopyToArray (array
, arrayIndex
, EnumeratorMode
.VALUE_MODE
);
1069 public virtual IEnumerator
GetEnumerator ()
1071 return new Hashtable
.Enumerator (host
, EnumeratorMode
.VALUE_MODE
);
1077 private class SyncHashtable
: Hashtable
, IEnumerable
{
1079 private Hashtable host
;
1081 public SyncHashtable (Hashtable host
) {
1083 throw new ArgumentNullException ();
1088 internal SyncHashtable (SerializationInfo info
, StreamingContext context
)
1090 host
= (Hashtable
) info
.GetValue("ParentTable", typeof(Hashtable
));
1093 public override void GetObjectData (SerializationInfo info
, StreamingContext context
)
1095 info
.AddValue ("ParentTable", host
);
1100 public override int Count
{
1106 public override bool IsSynchronized
{
1112 public override Object SyncRoot
{
1114 return host
.SyncRoot
;
1122 public override bool IsFixedSize
{
1124 return host
.IsFixedSize
;
1129 public override bool IsReadOnly
{
1131 return host
.IsReadOnly
;
1135 public override ICollection Keys
{
1137 ICollection keys
= null;
1138 lock (host
.SyncRoot
) {
1145 public override ICollection Values
{
1147 ICollection vals
= null;
1148 lock (host
.SyncRoot
) {
1157 public override Object
this [Object key
] {
1162 lock (host
.SyncRoot
) {
1170 IEnumerator IEnumerable
.GetEnumerator ()
1172 return new Enumerator (host
, EnumeratorMode
.ENTRY_MODE
);
1180 public override void CopyTo (Array array
, int arrayIndex
)
1182 host
.CopyTo (array
, arrayIndex
);
1188 public override void Add (Object key
, Object
value)
1190 lock (host
.SyncRoot
) {
1191 host
.Add (key
, value);
1195 public override void Clear ()
1197 lock (host
.SyncRoot
) {
1202 public override bool Contains (Object key
)
1204 return (host
.Find (key
) >= 0);
1207 public override IDictionaryEnumerator
GetEnumerator ()
1209 return new Enumerator (host
, EnumeratorMode
.ENTRY_MODE
);
1212 public override void Remove (Object key
)
1214 lock (host
.SyncRoot
) {
1221 public override bool ContainsKey (object key
)
1223 return host
.Contains (key
);
1226 public override bool ContainsValue (object value)
1228 return host
.ContainsValue (value);
1234 public override object Clone ()
1236 lock(host
.SyncRoot
) {
1237 return new SyncHashtable( (Hashtable
) host
.Clone () );