ReferenceEquals を使用する IEqualityComparer<T>
-
19-09-2019 - |
質問
デフォルトはありますか IEqualityComparer<T>
を使用する実装 ReferenceEquals
?
EqualityComparer<T>.Default
ObjectComparer を使用します。 object.Equals()
. 。私の場合、オブジェクトはすでに実装されています IEquatable<T>
, 、これは無視し、オブジェクトの参照のみで比較する必要があります。
解決
デフォルトの実装がない場合に備えて、これは私自身のものです。
280Z28による編集:使用の理論的根拠 RuntimeHelpers.GetHashCode(object)
, 、おそらくこれまで見たことがない人も多いでしょう。:) この方法には 2 つの効果があり、 正しい この実装を呼び出します。
- オブジェクトが null の場合は 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
}
他のヒント
私はそれはIEqualityComparer<in T>
インターフェイス上contravarianceに非ジェネリックのおかげになることで、簡素化.Net4.0 +に以前の回答の実装を更新するための時間だと思った。
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);
}
}
これが唯一のケースは前にあったように、すべてのリファレンスの同一性は、それぞれのタイプのT
に1つの代わりにチェックするためのインスタンスを存在する必要があります。
また、あなたはT
あなたがこれを使用するたびに指定する必要がないため、タイピングを節約!
共変性と反変性するの概念に精通していない人のために明らかにするために..ます。
class MyClass
{
ISet<MyClass> setOfMyClass = new HashSet<MyClass>(ReferenceEqualityComparer.Default);
}
...うまく動作します。これは、 のない、例えばこれらに限定されていますHashSet<object>
又は(.Net4.0で)類似している。
また疑問誰にとってなぜx == y
operatorは、それがコンパイル時に解決されることを意味静的方法であり、コンパイル時に、xおよびyがので、ここでそれが解決タイプ==
であるためobject
は、基準等価です==
のobject
operator - の本当のの参照の等価方法です。 (オブジェクトへのリダイレクトは、オペレータに等しい単に実際Object.ReferenceEquals(object, 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
改質剤の3つの文字に多くのパラグラフを捧げました。さんがまとめてみましょう。
単一の定義されたインスタンスEquals(object,object)
方法はこのタイプ、Equals
そのジェネリック相手IEqualityComparer
のための2つの宣言されたインターフェースの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
で十分と他の人に、より明確に意図を説明します。
別の方法として次の2つのインターフェイスEquals
メソッドの明示的な実装を使用することができますが、あなたはReferenceEqualityComparer.Default.Equals(a,b)
を使用した場合、あなたはすべての基準平等を持っていないでしょう。
は、実際には、インスタンスメソッドと静的メソッドを隠蔽することはめったに問題ではありません。それはあなたがFoo.StaticMethod()
ないnew Foo().StaticMethod()
を使用し、です。インスタンスからの静的メソッドを呼び出すと、最悪の場合、誤った/最高で不要と誤解を招く恐れがあります。
さらに、平等する比較器のために、あなたはめったに自分の具体的な種類を直接使用しません。むしろ、あなたは、このようなコレクションとしてのAPIでそれらを使用します。
これはされたがだから面白いと議論を混乱の回で、それはかなり無益だっます。
MicrosoftはObjectReferenceEqualityComparer
でSystem.Data.Entity.Infrastructure
を提供しています。
ただ、比較演算子としてObjectReferenceEqualityComparer.Default
を使用します。