を使用するデフォルトのIEqualityComparer<T>
実装はありますReferenceEquals
か?
EqualityComparer<T>.Default
を使用する ObjectComparer を使用しますobject.Equals()
。私の場合、オブジェクトは既に を実装していますがIEquatable<T>
、これは無視してオブジェクトの参照のみで比較する必要があります。
を使用するデフォルトのIEqualityComparer<T>
実装はありますReferenceEquals
か?
EqualityComparer<T>.Default
を使用する ObjectComparer を使用しますobject.Equals()
。私の場合、オブジェクトは既に を実装していますがIEquatable<T>
、これは無視してオブジェクトの参照のみで比較する必要があります。
デフォルトの実装がない場合に備えて、これは私自身のものです:
280Z28 による編集: を使用する理由RuntimeHelpers.GetHashCode(object)
、これまでに見たことがない人も多いでしょう。:) このメソッドには、この実装の正しい呼び出しとなる 2 つの効果があります。
ReferenceEquals
、比較子の 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>
以前の回答の実装を.Net4.0 +に更新する時が来たと思いました.Net4.0 +では、インターフェイスの反変性のおかげでジェネリックは不要になりました。
using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
public sealed class ReferenceEqualityComparer
: IEqualityComparer, IEqualityComparer<object>
{
private ReferenceEqualityComparer() { }
public static readonly ReferenceEqualityComparer Default
= new ReferenceEqualityComparer();
public /*new*/ 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);
}
}
これで、以前のように型ごとに 1 つのインスタンスが存在するのではなく、すべての参照等価性チェックに対して 1 つのインスタンスが存在するだけで済みますT
。
T
これを使用するたびに指定する必要がなくなり、不要なジェネリック ランタイム タイプによる汚染も回避できます。
x == y
参照が等しい理由については、==
演算子が静的メソッドであるためです。つまり、コンパイル時に解決され、コンパイル時に引数x
とy
引数の型がobject
.
実際、Object.ReferenceEquals(object, object)
メソッドのソース コードは次のようになります。
public static bool ReferenceEquals(object objA, object objB) {
return objA == objB;
}
共分散と反分散の概念に慣れていない人のために明確にするために...
class MyClass
{
ISet<MyClass> setOfMyClass = new HashSet<MyClass>(ReferenceEqualityComparer.Default);
}
...上記のコードはコンパイルされます。とは言っていないことに注意してくださいHashSet<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);
}
または、参照型でのみ使用できることを保証する汎用バージョン:
public sealed class ReferenceEqualityComparer<T> : IEqualityComparer<T> where T : class
{
public static IEqualityComparer<T> Default { get; } = new ReferenceEqualityComparer<T>();
public bool Equals(T x, T y) => ReferenceEquals(x, y);
public int GetHashCode(T obj) => RuntimeHelpers.GetHashCode(obj);
}