Yur*_*rik 57 .net c# iequalitycomparer referenceequals
是否有使用的默认IEqualityComparer<T>
实现ReferenceEquals
?
EqualityComparer<T>.Default
使用ObjectComparer,它使用object.Equals()
.在我的例子中,对象已经实现IEquatable<T>
,我需要忽略并仅通过对象的引用进行比较.
Yur*_*rik 56
为了防止没有默认实现,这是我自己的:
编辑280Z28:使用的理由RuntimeHelpers.GetHashCode(object)
,你们许多人可能以前从未见过.:)这个方法有两个效果,使它成为这个实现的正确调用:
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
}
Run Code Online (Sandbox Code Playgroud)
Ano*_*ken 16
我认为现在是时候将以前的答案实施更新到.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);
}
}
Run Code Online (Sandbox Code Playgroud)
现在只需要为所有引用相等性检查存在一个实例,而不是T
像以前那样为每种类型存在一个实例.
您也可以通过不必T
每次都要使用它来保存输入!
澄清那些不熟悉协方差和反演的概念......
class MyClass
{
ISet<MyClass> setOfMyClass = new HashSet<MyClass>(ReferenceEqualityComparer.Default);
}
Run Code Online (Sandbox Code Playgroud)
......会工作得很好.这并不限定于例如HashSet<object>
或相似的(在.Net4.0).
此外,任何人想知道为什么x == y
是引用相等,这是因为==
运营商是一个静态方法,这意味着它在编译时得到解决,并在编译时x和y型的object
所以在这里解析为==
运营商object
-这是真正的参考平等方法.(实际上该Object.ReferenceEquals(object, object)
方法只是重定向到对象equals运算符.)
这是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);
}
Run Code Online (Sandbox Code Playgroud)
编辑(除非您对以下评论感兴趣,否则您不必阅读此内容)
@AnorZaken在new
这里为修饰符的三个字母投入了许多段落.让我们总结一下.
单个定义的实例Equals(object,object)
方法实现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)
呢?因此,使用new
提供了明智和理想的行为,并允许编译没有警告.
你怎么能抑制警告?如果使用#pragma warning disable 108
/ #pragma warning restore 108
然后结果与使用相同new
,除非您为代码添加了更多噪声.new
足以满足并更清楚地向他人解释意图.
或者,您可以对两个接口Equals
方法使用显式实现,但是如果您使用了ReferenceEqualityComparer.Default.Equals(a,b)
,则根本不会具有引用相等性.
实际上,使用实例方法隐藏静态方法很少是一个问题,因为静态方法是从类型说明符而不是实例说明符中取消引用的.也就是说,你Foo.StaticMethod()
没有使用new Foo().StaticMethod()
.从实例调用静态方法充其量是不必要的,在最坏的情况下是误导/错误的.
此外,对于相等比较器,您很少直接使用它们的具体类型.相反,您可以将它们与API(如集合)一起使用.
因此,尽管这是一个有趣且有时令人困惑的讨论,但它却毫无结果.
归档时间: |
|
查看次数: |
7115 次 |
最近记录: |