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