1 // Licensed to the .NET Foundation under one or more agreements. 2 // The .NET Foundation licenses this file to you under the MIT license. 3 // See the LICENSE file in the project root for more information. 4 5 6 using System.Runtime.CompilerServices; 7 8 using Internal.IntrinsicSupport; 9 10 namespace System.Collections.Generic 11 { 12 [Serializable] 13 [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] 14 public abstract class EqualityComparer<T> : IEqualityComparer, IEqualityComparer<T> 15 { 16 // WARNING: We allow diagnostic tools to directly inspect this member (_default). 17 // See https://github.com/dotnet/corert/blob/master/Documentation/design-docs/diagnostics/diagnostics-tools-contract.md for more details. 18 // Please do not change the type, the name, or the semantic usage of this member without understanding the implication for tools. 19 // Get in touch with the diagnostics team if you have questions. 20 private static EqualityComparer<T> _default; 21 22 [Intrinsic] Create()23 private static EqualityComparer<T> Create() 24 { 25 #if PROJECTN 26 // The compiler will overwrite the Create method with optimized 27 // instantiation-specific implementation. 28 _default = null; 29 throw new NotSupportedException(); 30 #else 31 // The compiler will overwrite the Create method with optimized 32 // instantiation-specific implementation. 33 // This body serves as a fallback when instantiation-specific implementation is unavailable. 34 return (_default = EqualityComparerHelpers.GetUnknownEquatableComparer<T>()); 35 #endif 36 } 37 EqualityComparer()38 protected EqualityComparer() 39 { 40 } 41 42 public static EqualityComparer<T> Default 43 { 44 [Intrinsic] 45 get 46 { 47 // Lazy initialization produces smaller code for CoreRT than initialization in constructor 48 return _default ?? Create(); 49 } 50 } 51 Equals(T x, T y)52 public abstract bool Equals(T x, T y); 53 GetHashCode(T obj)54 public abstract int GetHashCode(T obj); 55 IEqualityComparer.GetHashCode(object obj)56 int IEqualityComparer.GetHashCode(object obj) 57 { 58 if (obj == null) 59 return 0; 60 if (obj is T) 61 return GetHashCode((T)obj); 62 throw new ArgumentException(SR.Argument_InvalidArgumentForComparison, nameof(obj)); 63 } 64 IEqualityComparer.Equals(object x, object y)65 bool IEqualityComparer.Equals(object x, object y) 66 { 67 if (x == y) 68 return true; 69 if (x == null || y == null) 70 return false; 71 if ((x is T) && (y is T)) 72 return Equals((T)x, (T)y); 73 throw new ArgumentException(SR.Argument_InvalidArgumentForComparison); 74 } 75 } 76 77 #if false 78 internal sealed class DefaultEqualityComparer<T> : EqualityComparer<T> 79 { DefaultEqualityComparer()80 public DefaultEqualityComparer() 81 { 82 } 83 Equals(T x, T y)84 public sealed override bool Equals(T x, T y) 85 { 86 if (x == null) 87 return y == null; 88 if (y == null) 89 return false; 90 91 return x.Equals(y); 92 } 93 GetHashCode(T obj)94 public sealed override int GetHashCode(T obj) 95 { 96 if (obj == null) 97 return 0; 98 return obj.GetHashCode(); 99 } 100 101 // Equals method for the comparer itself. Equals(Object obj)102 public sealed override bool Equals(Object obj) 103 { 104 if (obj == null) 105 { 106 return false; 107 } 108 109 // This needs to use GetType instead of typeof to avoid infinite recursion in the type loader 110 return obj.GetType().Equals(GetType()); 111 } 112 113 114 // This needs to use GetType instead of typeof to avoid infinite recursion in the type loader GetHashCode()115 public sealed override int GetHashCode() => GetType().GetHashCode(); 116 } 117 #endif 118 } 119