1 // ==++==
2 //
3 //   Copyright (c) Microsoft Corporation.  All rights reserved.
4 //
5 // ==--==
6 // <OWNER>Microsoft</OWNER>
7 //
8 
9 using System;
10 using System.Collections;
11 using System.Collections.Generic;
12 using System.Security;
13 using System.Runtime.Serialization;
14 
15 namespace System.Collections.Generic
16 {
17     using System.Globalization;
18     using System.Runtime;
19     using System.Runtime.CompilerServices;
20     using System.Diagnostics.Contracts;
21 
22     [Serializable]
23     [TypeDependencyAttribute("System.Collections.Generic.ObjectEqualityComparer`1")]
24     public abstract class EqualityComparer<T> : IEqualityComparer, IEqualityComparer<T>
25     {
26         static volatile EqualityComparer<T> defaultComparer;
27 
28         public static EqualityComparer<T> Default {
29             get {
30                 Contract.Ensures(Contract.Result<EqualityComparer<T>>() != null);
31 
32                 EqualityComparer<T> comparer = defaultComparer;
33                 if (comparer == null) {
34                     comparer = CreateComparer();
35                     defaultComparer = comparer;
36                 }
37                 return comparer;
38             }
39         }
40 
41         //
42         // Note that logic in this method is replicated in vm\compile.cpp to ensure that NGen
43         // saves the right instantiations
44         //
45         [System.Security.SecuritySafeCritical]  // auto-generated
CreateComparer()46         private static EqualityComparer<T> CreateComparer() {
47             Contract.Ensures(Contract.Result<EqualityComparer<T>>() != null);
48 
49             RuntimeType t = (RuntimeType)typeof(T);
50             // Specialize type byte for performance reasons
51             if (t == typeof(byte)) {
52                 return (EqualityComparer<T>)(object)(new ByteEqualityComparer());
53             }
54 
55 #if MOBILE
56             // Breaks .net serialization compatibility
57             if (t == typeof (string))
58                 return (EqualityComparer<T>)(object)new InternalStringComparer ();
59 #endif
60 
61             // If T implements IEquatable<T> return a GenericEqualityComparer<T>
62             if (typeof(IEquatable<T>).IsAssignableFrom(t)) {
63 #if MONO
64                 return (EqualityComparer<T>)RuntimeType.CreateInstanceForAnotherGenericParameter (typeof(GenericEqualityComparer<>), t);
65 #else
66                 return (EqualityComparer<T>)RuntimeTypeHandle.CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(GenericEqualityComparer<int>), t);
67 #endif
68             }
69             // If T is a Nullable<U> where U implements IEquatable<U> return a NullableEqualityComparer<U>
70             if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>)) {
71                 RuntimeType u = (RuntimeType)t.GetGenericArguments()[0];
72                 if (typeof(IEquatable<>).MakeGenericType(u).IsAssignableFrom(u)) {
73 #if MONO
74                     return (EqualityComparer<T>)RuntimeType.CreateInstanceForAnotherGenericParameter (typeof(NullableEqualityComparer<>), u);
75 #else
76                     return (EqualityComparer<T>)RuntimeTypeHandle.CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(NullableEqualityComparer<int>), u);
77 #endif
78                 }
79             }
80 
81             // See the METHOD__JIT_HELPERS__UNSAFE_ENUM_CAST and METHOD__JIT_HELPERS__UNSAFE_ENUM_CAST_LONG cases in getILIntrinsicImplementation
82             if (t.IsEnum) {
83                 TypeCode underlyingTypeCode = Type.GetTypeCode(Enum.GetUnderlyingType(t));
84 
85                 // Depending on the enum type, we need to special case the comparers so that we avoid boxing
86                 // Note: We have different comparers for Short and SByte because for those types we need to make sure we call GetHashCode on the actual underlying type as the
87                 // implementation of GetHashCode is more complex than for the other types.
88                 switch (underlyingTypeCode) {
89                     case TypeCode.Int16: // short
90 #if MONO
91                         return (EqualityComparer<T>)RuntimeType.CreateInstanceForAnotherGenericParameter (typeof(ShortEnumEqualityComparer<>), t);
92 #else
93                         return (EqualityComparer<T>)RuntimeTypeHandle.CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(ShortEnumEqualityComparer<short>), t);
94 #endif
95                     case TypeCode.SByte:
96 #if MONO
97                         return (EqualityComparer<T>)RuntimeType.CreateInstanceForAnotherGenericParameter (typeof(SByteEnumEqualityComparer<>), t);
98 #else
99                         return (EqualityComparer<T>)RuntimeTypeHandle.CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(SByteEnumEqualityComparer<sbyte>), t);
100 #endif
101                     case TypeCode.Int32:
102                     case TypeCode.UInt32:
103                     case TypeCode.Byte:
104                     case TypeCode.UInt16: //ushort
105 #if MONO
106                         return (EqualityComparer<T>)RuntimeType.CreateInstanceForAnotherGenericParameter (typeof(EnumEqualityComparer<>), t);
107 #else
108                         return (EqualityComparer<T>)RuntimeTypeHandle.CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(EnumEqualityComparer<int>), t);
109 #endif
110                     case TypeCode.Int64:
111                     case TypeCode.UInt64:
112 #if MONO
113                         return (EqualityComparer<T>)RuntimeType.CreateInstanceForAnotherGenericParameter (typeof(LongEnumEqualityComparer<>), t);
114 #else
115                         return (EqualityComparer<T>)RuntimeTypeHandle.CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(LongEnumEqualityComparer<long>), t);
116 #endif
117                 }
118             }
119             // Otherwise return an ObjectEqualityComparer<T>
120             return new ObjectEqualityComparer<T>();
121         }
122 
123         [Pure]
Equals(T x, T y)124         public abstract bool Equals(T x, T y);
125         [Pure]
GetHashCode(T obj)126         public abstract int GetHashCode(T obj);
127 
IndexOf(T[] array, T value, int startIndex, int count)128         internal virtual int IndexOf(T[] array, T value, int startIndex, int count) {
129             int endIndex = startIndex + count;
130             for (int i = startIndex; i < endIndex; i++) {
131                 if (Equals(array[i], value)) return i;
132             }
133             return -1;
134         }
135 
LastIndexOf(T[] array, T value, int startIndex, int count)136         internal virtual int LastIndexOf(T[] array, T value, int startIndex, int count) {
137             int endIndex = startIndex - count + 1;
138             for (int i = startIndex; i >= endIndex; i--) {
139                 if (Equals(array[i], value)) return i;
140             }
141             return -1;
142         }
143 
IEqualityComparer.GetHashCode(object obj)144         int IEqualityComparer.GetHashCode(object obj) {
145             if (obj == null) return 0;
146             if (obj is T) return GetHashCode((T)obj);
147             ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidArgumentForComparison);
148             return 0;
149         }
150 
IEqualityComparer.Equals(object x, object y)151         bool IEqualityComparer.Equals(object x, object y) {
152             if (x == y) return true;
153             if (x == null || y == null) return false;
154             if ((x is T) && (y is T)) return Equals((T)x, (T)y);
155             ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidArgumentForComparison);
156             return false;
157         }
158     }
159 
160     // The methods in this class look identical to the inherited methods, but the calls
161     // to Equal bind to IEquatable<T>.Equals(T) instead of Object.Equals(Object)
162     [Serializable]
163     internal class GenericEqualityComparer<T>: EqualityComparer<T> where T: IEquatable<T>
164     {
165         [Pure]
Equals(T x, T y)166         public override bool Equals(T x, T y) {
167             if (x != null) {
168                 if (y != null) return x.Equals(y);
169                 return false;
170             }
171             if (y != null) return false;
172             return true;
173         }
174 
175         [Pure]
GetHashCode(T obj)176         public override int GetHashCode(T obj) {
177             if (obj == null) return 0;
178             return obj.GetHashCode();
179         }
180 
IndexOf(T[] array, T value, int startIndex, int count)181         internal override int IndexOf(T[] array, T value, int startIndex, int count) {
182             int endIndex = startIndex + count;
183             if (value == null) {
184                 for (int i = startIndex; i < endIndex; i++) {
185                     if (array[i] == null) return i;
186                 }
187             }
188             else {
189                 for (int i = startIndex; i < endIndex; i++) {
190                     if (array[i] != null && array[i].Equals(value)) return i;
191                 }
192             }
193             return -1;
194         }
195 
LastIndexOf(T[] array, T value, int startIndex, int count)196         internal override int LastIndexOf(T[] array, T value, int startIndex, int count) {
197             int endIndex = startIndex - count + 1;
198             if (value == null) {
199                 for (int i = startIndex; i >= endIndex; i--) {
200                     if (array[i] == null) return i;
201                 }
202             }
203             else {
204                 for (int i = startIndex; i >= endIndex; i--) {
205                     if (array[i] != null && array[i].Equals(value)) return i;
206                 }
207             }
208             return -1;
209         }
210 
211         // Equals method for the comparer itself.
Equals(Object obj)212         public override bool Equals(Object obj){
213             GenericEqualityComparer<T> comparer = obj as GenericEqualityComparer<T>;
214             return comparer != null;
215         }
216 
GetHashCode()217         public override int GetHashCode() {
218             return this.GetType().Name.GetHashCode();
219         }
220     }
221 
222     [Serializable]
223     internal class NullableEqualityComparer<T> : EqualityComparer<Nullable<T>> where T : struct, IEquatable<T>
224     {
225         [Pure]
Equals(Nullable<T> x, Nullable<T> y)226         public override bool Equals(Nullable<T> x, Nullable<T> y) {
227             if (x.HasValue) {
228                 if (y.HasValue) return x.value.Equals(y.value);
229                 return false;
230             }
231             if (y.HasValue) return false;
232             return true;
233         }
234 
235         [Pure]
GetHashCode(Nullable<T> obj)236         public override int GetHashCode(Nullable<T> obj) {
237             return obj.GetHashCode();
238         }
239 
IndexOf(Nullable<T>[] array, Nullable<T> value, int startIndex, int count)240         internal override int IndexOf(Nullable<T>[] array, Nullable<T> value, int startIndex, int count) {
241             int endIndex = startIndex + count;
242             if (!value.HasValue) {
243                 for (int i = startIndex; i < endIndex; i++) {
244                     if (!array[i].HasValue) return i;
245                 }
246             }
247             else {
248                 for (int i = startIndex; i < endIndex; i++) {
249                     if (array[i].HasValue && array[i].value.Equals(value.value)) return i;
250                 }
251             }
252             return -1;
253         }
254 
LastIndexOf(Nullable<T>[] array, Nullable<T> value, int startIndex, int count)255         internal override int LastIndexOf(Nullable<T>[] array, Nullable<T> value, int startIndex, int count) {
256             int endIndex = startIndex - count + 1;
257             if (!value.HasValue) {
258                 for (int i = startIndex; i >= endIndex; i--) {
259                     if (!array[i].HasValue) return i;
260                 }
261             }
262             else {
263                 for (int i = startIndex; i >= endIndex; i--) {
264                     if (array[i].HasValue && array[i].value.Equals(value.value)) return i;
265                 }
266             }
267             return -1;
268         }
269 
270         // Equals method for the comparer itself.
Equals(Object obj)271         public override bool Equals(Object obj){
272             NullableEqualityComparer<T> comparer = obj as NullableEqualityComparer<T>;
273             return comparer != null;
274         }
275 
GetHashCode()276         public override int GetHashCode() {
277             return this.GetType().Name.GetHashCode();
278         }
279     }
280 
281     [Serializable]
282     internal class ObjectEqualityComparer<T>: EqualityComparer<T>
283     {
284         [Pure]
Equals(T x, T y)285         public override bool Equals(T x, T y) {
286             if (x != null) {
287                 if (y != null) return x.Equals(y);
288                 return false;
289             }
290             if (y != null) return false;
291             return true;
292         }
293 
294         [Pure]
GetHashCode(T obj)295         public override int GetHashCode(T obj) {
296             if (obj == null) return 0;
297             return obj.GetHashCode();
298         }
299 
IndexOf(T[] array, T value, int startIndex, int count)300         internal override int IndexOf(T[] array, T value, int startIndex, int count) {
301             int endIndex = startIndex + count;
302             if (value == null) {
303                 for (int i = startIndex; i < endIndex; i++) {
304                     if (array[i] == null) return i;
305                 }
306             }
307             else {
308                 for (int i = startIndex; i < endIndex; i++) {
309                     if (array[i] != null && array[i].Equals(value)) return i;
310                 }
311             }
312             return -1;
313         }
314 
LastIndexOf(T[] array, T value, int startIndex, int count)315         internal override int LastIndexOf(T[] array, T value, int startIndex, int count) {
316             int endIndex = startIndex - count + 1;
317             if (value == null) {
318                 for (int i = startIndex; i >= endIndex; i--) {
319                     if (array[i] == null) return i;
320                 }
321             }
322             else {
323                 for (int i = startIndex; i >= endIndex; i--) {
324                     if (array[i] != null && array[i].Equals(value)) return i;
325                 }
326             }
327             return -1;
328         }
329 
330         // Equals method for the comparer itself.
Equals(Object obj)331         public override bool Equals(Object obj){
332             ObjectEqualityComparer<T> comparer = obj as ObjectEqualityComparer<T>;
333             return comparer != null;
334         }
335 
GetHashCode()336         public override int GetHashCode() {
337             return this.GetType().Name.GetHashCode();
338         }
339     }
340 
341 #if FEATURE_CORECLR
342     // NonRandomizedStringEqualityComparer is the comparer used by default with the Dictionary<string,...>
343     // As the randomized string hashing is turned on by default on coreclr, we need to keep the performance not affected
344     // as much as possible in the main stream scenarios like Dictionary<string,�>
345     // We use NonRandomizedStringEqualityComparer as default comparer as it doesn�t use the randomized string hashing which
346     // keep the perofrmance not affected till we hit collision threshold and then we switch to the comparer which is using
347     // randomized string hashing GenericEqualityComparer<string>
348 
349     internal class NonRandomizedStringEqualityComparer : GenericEqualityComparer<string> {
350         static IEqualityComparer<string> s_nonRandomizedComparer;
351 
352         internal static IEqualityComparer<string> Default {
353             get  {
354                     if (s_nonRandomizedComparer == null) {
355                         s_nonRandomizedComparer = new NonRandomizedStringEqualityComparer();
356                     }
357                     return s_nonRandomizedComparer;
358             }
359         }
360 
361         [Pure]
GetHashCode(string obj)362         public override int GetHashCode(string obj)  {
363             if (obj == null) return 0;
364             return obj.GetLegacyNonRandomizedHashCode();
365         }
366     }
367 #endif // FEATURE_CORECLR
368 
369     // Performance of IndexOf on byte array is very important for some scenarios.
370     // We will call the C runtime function memchr, which is optimized.
371     [Serializable]
372     internal class ByteEqualityComparer: EqualityComparer<byte>
373     {
374         [Pure]
Equals(byte x, byte y)375         public override bool Equals(byte x, byte y) {
376             return x == y;
377         }
378 
379         [Pure]
GetHashCode(byte b)380         public override int GetHashCode(byte b) {
381             return b.GetHashCode();
382         }
383 
384         [System.Security.SecuritySafeCritical]  // auto-generated
IndexOf(byte[] array, byte value, int startIndex, int count)385         internal unsafe override int IndexOf(byte[] array, byte value, int startIndex, int count) {
386             if (array==null)
387                 throw new ArgumentNullException("array");
388             if (startIndex < 0)
389                 throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_Index"));
390             if (count < 0)
391                 throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_Count"));
392             if (count > array.Length - startIndex)
393                 throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen"));
394             Contract.EndContractBlock();
395             if (count == 0) return -1;
396             fixed (byte* pbytes = array) {
397                 return Buffer.IndexOfByte(pbytes, value, startIndex, count);
398             }
399         }
400 
LastIndexOf(byte[] array, byte value, int startIndex, int count)401         internal override int LastIndexOf(byte[] array, byte value, int startIndex, int count) {
402             int endIndex = startIndex - count + 1;
403             for (int i = startIndex; i >= endIndex; i--) {
404                 if (array[i] == value) return i;
405             }
406             return -1;
407         }
408 
409         // Equals method for the comparer itself.
Equals(Object obj)410         public override bool Equals(Object obj){
411             ByteEqualityComparer comparer = obj as ByteEqualityComparer;
412             return comparer != null;
413         }
414 
GetHashCode()415         public override int GetHashCode() {
416             return this.GetType().Name.GetHashCode();
417         }
418     }
419 
420     [Serializable]
421     internal class EnumEqualityComparer<T> : EqualityComparer<T>, ISerializable where T : struct
422     {
423         [Pure]
Equals(T x, T y)424         public override bool Equals(T x, T y) {
425             int x_final = System.Runtime.CompilerServices.JitHelpers.UnsafeEnumCast(x);
426             int y_final = System.Runtime.CompilerServices.JitHelpers.UnsafeEnumCast(y);
427             return x_final == y_final;
428         }
429 
430         [Pure]
GetHashCode(T obj)431         public override int GetHashCode(T obj) {
432             int x_final = System.Runtime.CompilerServices.JitHelpers.UnsafeEnumCast(obj);
433             return x_final.GetHashCode();
434         }
435 
EnumEqualityComparer()436         public EnumEqualityComparer() { }
437 
438         // This is used by the serialization engine.
EnumEqualityComparer(SerializationInfo information, StreamingContext context)439         protected EnumEqualityComparer(SerializationInfo information, StreamingContext context) { }
440 
441         [SecurityCritical]
GetObjectData(SerializationInfo info, StreamingContext context)442         public void GetObjectData(SerializationInfo info, StreamingContext context) {
443             // For back-compat we need to serialize the comparers for enums with underlying types other than int as ObjectEqualityComparer
444             if (Type.GetTypeCode(Enum.GetUnderlyingType(typeof(T))) != TypeCode.Int32) {
445                 info.SetType(typeof(ObjectEqualityComparer<T>));
446             }
447         }
448 
449         // Equals method for the comparer itself.
Equals(Object obj)450         public override bool Equals(Object obj){
451             EnumEqualityComparer<T> comparer = obj as EnumEqualityComparer<T>;
452             return comparer != null;
453         }
454 
GetHashCode()455         public override int GetHashCode() {
456             return this.GetType().Name.GetHashCode();
457         }
458     }
459 
460     [Serializable]
461     internal sealed class SByteEnumEqualityComparer<T> : EnumEqualityComparer<T>, ISerializable where T : struct
462     {
SByteEnumEqualityComparer()463         public SByteEnumEqualityComparer() { }
464 
465         // This is used by the serialization engine.
SByteEnumEqualityComparer(SerializationInfo information, StreamingContext context)466         public SByteEnumEqualityComparer(SerializationInfo information, StreamingContext context) { }
467 
468         [Pure]
GetHashCode(T obj)469         public override int GetHashCode(T obj) {
470             int x_final = System.Runtime.CompilerServices.JitHelpers.UnsafeEnumCast(obj);
471             return ((sbyte)x_final).GetHashCode();
472         }
473     }
474 
475     [Serializable]
476     internal sealed class ShortEnumEqualityComparer<T> : EnumEqualityComparer<T>, ISerializable where T : struct
477     {
ShortEnumEqualityComparer()478         public ShortEnumEqualityComparer() { }
479 
480         // This is used by the serialization engine.
ShortEnumEqualityComparer(SerializationInfo information, StreamingContext context)481         public ShortEnumEqualityComparer(SerializationInfo information, StreamingContext context) { }
482 
483         [Pure]
GetHashCode(T obj)484         public override int GetHashCode(T obj) {
485             int x_final = System.Runtime.CompilerServices.JitHelpers.UnsafeEnumCast(obj);
486             return ((short)x_final).GetHashCode();
487         }
488     }
489 
490     [Serializable]
491     internal sealed class LongEnumEqualityComparer<T> : EqualityComparer<T>, ISerializable where T : struct
492     {
493         [Pure]
Equals(T x, T y)494         public override bool Equals(T x, T y) {
495             long x_final = System.Runtime.CompilerServices.JitHelpers.UnsafeEnumCastLong(x);
496             long y_final = System.Runtime.CompilerServices.JitHelpers.UnsafeEnumCastLong(y);
497             return x_final == y_final;
498         }
499 
500         [Pure]
GetHashCode(T obj)501         public override int GetHashCode(T obj) {
502             long x_final = System.Runtime.CompilerServices.JitHelpers.UnsafeEnumCastLong(obj);
503             return x_final.GetHashCode();
504         }
505 
506         // Equals method for the comparer itself.
Equals(Object obj)507         public override bool Equals(Object obj){
508             LongEnumEqualityComparer<T> comparer = obj as LongEnumEqualityComparer<T>;
509             return comparer != null;
510         }
511 
GetHashCode()512         public override int GetHashCode() {
513             return this.GetType().Name.GetHashCode();
514         }
515 
LongEnumEqualityComparer()516         public LongEnumEqualityComparer() { }
517 
518         // This is used by the serialization engine.
LongEnumEqualityComparer(SerializationInfo information, StreamingContext context)519         public LongEnumEqualityComparer(SerializationInfo information, StreamingContext context) { }
520 
521         [SecurityCritical]
GetObjectData(SerializationInfo info, StreamingContext context)522         public void GetObjectData(SerializationInfo info, StreamingContext context)
523         {
524             // The LongEnumEqualityComparer does not exist on 4.0 so we need to serialize this comparer as ObjectEqualityComparer
525             // to allow for roundtrip between 4.0 and 4.5.
526             info.SetType(typeof(ObjectEqualityComparer<T>));
527         }
528     }
529 
530     [Serializable]
531     sealed class InternalStringComparer : EqualityComparer<string> {
532 
GetHashCode(string obj)533         public override int GetHashCode (string obj)
534         {
535             if (obj == null)
536                 return 0;
537             return obj.GetHashCode ();
538         }
539 
Equals(string x, string y)540         public override bool Equals (string x, string y)
541         {
542             if (x == null)
543                 return y == null;
544 
545             if ((object) x == (object) y)
546                 return true;
547 
548             return x.Equals (y);
549         }
550 
IndexOf(string[] array, string value, int startIndex, int count)551         internal override int IndexOf (string[] array, string value, int startIndex, int count)
552         {
553             int endIndex = startIndex + count;
554             for (int i = startIndex; i < endIndex; ++i) {
555                 if (Array.UnsafeLoad (array, i) == value)
556                     return i;
557             }
558 
559             return -1;
560         }
561     }
562 
563 #if FEATURE_RANDOMIZED_STRING_HASHING
564     // This type is not serializeable by design.  It does not exist in previous versions and will be removed
565     // Once we move the framework to using secure hashing by default.
566     internal sealed class RandomizedStringEqualityComparer : IEqualityComparer<String>, IEqualityComparer, IWellKnownStringEqualityComparer
567     {
568         private long _entropy;
569 
RandomizedStringEqualityComparer()570         public RandomizedStringEqualityComparer() {
571             _entropy = HashHelpers.GetEntropy();
572         }
573 
Equals(object x, object y)574         public new bool Equals(object x, object y) {
575             if (x == y) return true;
576             if (x == null || y == null) return false;
577             if ((x is string) && (y is string)) return Equals((string)x, (string)y);
578             ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidArgumentForComparison);
579             return false;
580         }
581 
582         [Pure]
Equals(string x, string y)583         public bool Equals(string x, string y) {
584             if (x != null) {
585                 if (y != null) return x.Equals(y);
586                 return false;
587             }
588             if (y != null) return false;
589             return true;
590         }
591 
592         [Pure]
593         [SecuritySafeCritical]
GetHashCode(String obj)594         public int GetHashCode(String obj) {
595             if(obj == null) return 0;
596             return String.InternalMarvin32HashString(obj, obj.Length, _entropy);
597         }
598 
599         [Pure]
600         [SecuritySafeCritical]
GetHashCode(Object obj)601         public int GetHashCode(Object obj) {
602             if(obj == null) return 0;
603 
604             string sObj = obj as string;
605             if(sObj != null) return  String.InternalMarvin32HashString(sObj, sObj.Length, _entropy);
606 
607             return obj.GetHashCode();
608         }
609 
610         // Equals method for the comparer itself.
Equals(Object obj)611         public override bool Equals(Object obj) {
612             RandomizedStringEqualityComparer comparer = obj as RandomizedStringEqualityComparer;
613             return (comparer != null) && (this._entropy == comparer._entropy);
614         }
615 
GetHashCode()616         public override int GetHashCode() {
617             return (this.GetType().Name.GetHashCode() ^ ((int) (_entropy & 0x7FFFFFFF)));
618         }
619 
620 
IWellKnownStringEqualityComparer.GetRandomizedEqualityComparer()621         IEqualityComparer IWellKnownStringEqualityComparer.GetRandomizedEqualityComparer() {
622             return new RandomizedStringEqualityComparer();
623         }
624 
625         // We want to serialize the old comparer.
IWellKnownStringEqualityComparer.GetEqualityComparerForSerialization()626         IEqualityComparer IWellKnownStringEqualityComparer.GetEqualityComparerForSerialization() {
627             return EqualityComparer<string>.Default;
628         }
629     }
630 
631     // This type is not serializeable by design.  It does not exist in previous versions and will be removed
632     // Once we move the framework to using secure hashing by default.
633     internal sealed class RandomizedObjectEqualityComparer : IEqualityComparer, IWellKnownStringEqualityComparer
634     {
635         private long _entropy;
636 
RandomizedObjectEqualityComparer()637         public RandomizedObjectEqualityComparer() {
638             _entropy = HashHelpers.GetEntropy();
639         }
640 
641         [Pure]
Equals(Object x, Object y)642         public new bool Equals(Object x, Object y) {
643             if (x != null) {
644                 if (y != null) return x.Equals(y);
645                 return false;
646             }
647             if (y != null) return false;
648             return true;
649         }
650 
651         [Pure]
652         [SecuritySafeCritical]
GetHashCode(Object obj)653         public int GetHashCode(Object obj) {
654             if(obj == null) return 0;
655 
656             string sObj = obj as string;
657             if(sObj != null) return  String.InternalMarvin32HashString(sObj, sObj.Length, _entropy);
658 
659             return obj.GetHashCode();
660         }
661 
662         // Equals method for the comparer itself.
Equals(Object obj)663         public override bool Equals(Object obj){
664             RandomizedObjectEqualityComparer comparer = obj as RandomizedObjectEqualityComparer;
665             return (comparer != null) && (this._entropy == comparer._entropy);
666         }
667 
GetHashCode()668         public override int GetHashCode() {
669             return (this.GetType().Name.GetHashCode() ^ ((int) (_entropy & 0x7FFFFFFF)));
670         }
671 
IWellKnownStringEqualityComparer.GetRandomizedEqualityComparer()672         IEqualityComparer IWellKnownStringEqualityComparer.GetRandomizedEqualityComparer() {
673             return new RandomizedObjectEqualityComparer();
674         }
675 
676         // We want to serialize the old comparer, which in this case was null.
IWellKnownStringEqualityComparer.GetEqualityComparerForSerialization()677         IEqualityComparer IWellKnownStringEqualityComparer.GetEqualityComparerForSerialization() {
678             return null;
679         }
680     }
681 #endif
682 }
683 
684