IEqualityComparer <T>使用ReferenceEquals
有没有使用ReferenceEquals的默认IEqualityComparer<T>实现? 
  EqualityComparer<T>.Default使用ObjectComparer,它使用object.Equals() 。 在我的情况下,对象已经实现了IEquatable<T> ,我只需要忽略和比较对象的引用。 
以防万一没有默认的实现,这是我自己的:
 编辑280Z28:使用RuntimeHelpers.GetHashCode(object)理由,你可能以前没有见过。  :)这个方法有两个效果,使它成为这个实现的正确调用: 
-  当对象为空时,它返回0。 由于
ReferenceEquals适用于null参数,所以比较器的GetHashCode()实现也是如此。 -  它非虚拟地调用
Object.GetHashCode()。ReferenceEquals特别忽略了Equals任何覆盖,所以GetHashCode()的实现应该使用特殊的方法来匹配ReferenceEquals的效果,这正是RuntimeHelpers.GetHashCode的作用。 
[结束280Z28]
 using System; using System.Collections.Generic; using System.Runtime.CompilerServices; /// <summary> /// A generic object comparerer that would only use object's reference, /// ignoring any <see cref="IEquatable{T}"/> or <see cref="object.Equals(object)"/> overrides. /// </summary> public class ObjectReferenceEqualityComparer<T> : EqualityComparer<T> where T : class { private static IEqualityComparer<T> _defaultComparer; public new static IEqualityComparer<T> Default { get { return _defaultComparer ?? (_defaultComparer = new ObjectReferenceEqualityComparer<T>()); } } #region IEqualityComparer<T> Members public override bool Equals(T x, T y) { return ReferenceEquals(x, y); } public override int GetHashCode(T obj) { return RuntimeHelpers.GetHashCode(obj); } #endregion } 
 我认为现在是时候把以前的答案更新到.Net4.0 +,通过在IEqualityComparer<in T>界面上的逆变而变得非泛化, 
 using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; public sealed class ReferenceEqualityComparer : IEqualityComparer, IEqualityComparer<object> { public static readonly ReferenceEqualityComparer Default = new ReferenceEqualityComparer(); // JIT-lazy is sufficiently lazy imo. private ReferenceEqualityComparer() { } // <-- A matter of opinion / style. public bool Equals(object x, object y) { return x == y; // This is reference equality! (See explanation below.) } public int GetHashCode(object obj) { return RuntimeHelpers.GetHashCode(obj); } } 
 现在只需要为所有引用相等检查存在一个实例,而不是每个typesT都有一个实例,就像以前一样。 
 你也可以节省打字时间,而不必在每次使用时都指定T ! 
澄清那些不熟悉协方差和反variables概念的人
 class MyClass { ISet<MyClass> setOfMyClass = new HashSet<MyClass>(ReferenceEqualityComparer.Default); } 
  …会工作得很好。 这不限于例如HashSet<object>或类似的(在.Net4.0中)。 
 对于任何想知道为什么x == y是引用相等的人,这是因为==运算符是一个静态方法,这意味着它在编译时被parsing,而在编译时x和y是typesobject所以在这里parsing为object的==运算符 – 这是真正的引用等式方法。  (实际上, Object.ReferenceEquals(object, object)方法只是一个redirect到object对象的操作符。) 
这是C#6的简单实现。
 public sealed class ReferenceEqualityComparer : IEqualityComparer, IEqualityComparer<object> { public static ReferenceEqualityComparer Default { get; } = new ReferenceEqualityComparer(); public new bool Equals(object x, object y) => ReferenceEquals(x, y); public int GetHashCode(object obj) => RuntimeHelpers.GetHashCode(obj); } 
编辑 (你不必读这个,除非你有兴趣在下面的评论)
  @AnorZaken在这里为new修饰语的三个字母写了许多段落。 我们总结一下。 
 单个定义的实例Equals(object,object)方法实现了这个types的两个声明接口的Equals方法, IEqualityComparer和它的通用对应的IEqualityComparer<object> 。 签名是相同的,所以这个定义满足两个接口。 
 实例方法ReferenceEqualityComparer.Equals(object,object)隐藏静态 object.Equals(object,object)方法。 
 没有new的编译器警告这一点。 这实际上是什么意思? 
 这意味着如果你想调用静态的object.Equals方法,你不能在ReferenceEqualityComparer的实例上调用它。 这是一个大问题吗? 
 不。事实上,这是期望的行为。 这意味着如果你想调用object.Equals(a,b)你不能通过ReferenceEqualityComparer.Default.Equals(a,b)等代码来完成。 该代码明确要求参考平等 – 没有人会合理地期望它执行默认/值的平等。 为什么不直接编写更明确的object.Equals(a,b)呢? object.Equals(a,b)呢? 所以new的使用提供了明智的和理想的行为,并且允许编译而不用警告。 
 你还可以怎样压制这个警告? 如果您使用#pragma warning disable 108 / #pragma warning restore 108则结果与使用new的结果相同,只是您已向代码中添加了更多噪声。  new足够,并更清楚地解释其他人的意图。 
 或者,你可以使用显式实现的两个接口Equals方法,但是如果你使用了ReferenceEqualityComparer.Default.Equals(a,b)你根本就没有引用的相等性。 
 实际上,使用实例方法隐藏静态方法几乎不是问题,因为静态方法是从types说明符中取消引用的,而不是实例说明符。 也就是说,你使用Foo.StaticMethod()而不是new Foo().StaticMethod() 。 从实例中调用静态方法是不必要的,最糟糕的是误导/不正确。 
而且,对于相等比较器,您很less直接使用它们的具体types。 而是将它们与API(如集合)一起使用。
所以虽然这是一个有趣的,有时令人困惑的讨论,但它是没有结果的。