IEqualityComparer<T>
および IEquatable<T>
を使用する必要があります。両方のMSDNドキュメントは非常に似ています。
IEqualityComparer<T>
は、T
型の2つのオブジェクトで比較を実行するオブジェクトのインターフェイスです。
IEquatable<T>
はT
型のオブジェクト用であるため、自分自身を別のオブジェクトと比較できます。
IEquatable<T>
または IEqualityComparer<T>
のどちらを使用するかを決定するとき、次のように尋ねることができます。
T
の2つのインスタンスが等しいかどうかをテストする好ましい方法はありますか、それとも同等に有効な方法がいくつかありますか?
T
の2つのインスタンスが等しいかどうかをテストする方法が1つしかない場合、またはいくつかのメソッドのいずれかが望ましい場合、IEquatable<T>
が正しい選択になります。このインターフェイスは、T
自体。したがって、T
の1つのインスタンスは、それ自体をT
の別のインスタンスと比較する方法に関する内部知識を持ちます。
一方、2つのT
が等しいかどうかを比較する同等の合理的な方法がいくつかある場合、IEqualityComparer<T>
はより適切に思えます。このインターフェイスはT
自体によって実装されることを意図していませんが他の「外部」クラスによる。したがって、T
の2つのインスタンスを等しいかどうかをテストする場合、T
には内部的に同等性の理解がないため、次のようにテストを実行するIEqualityComparer<T>
インスタンスを明示的に選択する必要があります特定の要件。
例:
これら2つのタイプ( 値のセマンティクス を持つことになっている)を考えてみましょう。
interface IIntPoint : IEquatable<IIntPoint>
{
int X { get; }
int Y { get; }
}
interface IDoublePoint // does not inherit IEquatable<IDoublePoint>; see below.
{
double X { get; }
double Y { get; }
}
なぜこれらのタイプの1つだけがIEquatable<>
を継承し、他のタイプは継承しないのですか?
理論的には、いずれかのタイプの2つのインスタンスを比較する賢明な方法は1つだけです。両方のインスタンスのX
プロパティとY
プロパティが等しい場合、それらは等しくなります。この考え方によれば、両方のタイプはIEquatable<>
を実装する必要があります。これは、同等性テストを行う他の意味のある方法があるとは思われないからです。
ここでの問題は、 同等の浮動小数点数を比較すると、微小な丸め誤差のために期待どおりに動作しない可能性がある です。 near-equalityの浮動小数点数を比較するさまざまな方法があり、それぞれに特定の利点とトレードオフがあり、どの方法が適切かを自分で選択できるようにしたい場合があります。
sealed class DoublePointNearEqualityComparerByTolerance : IEqualityComparer<IDoublePoint>
{
public DoublePointNearEqualityComparerByTolerance(double tolerance) { … }
…
public bool Equals(IDoublePoint a, IDoublePoint b)
{
return Math.Abs(a.X - b.X) <= tolerance && Math.Abs(a.Y - b.Y) <= tolerance;
}
…
}
(上記)にリンクしたページには、この平等に近いテストには弱点があることが明示的に示されていることに注意してください。これはIEqualityComparer<T>
実装であるため、目的に十分でない場合は単純に交換できます。
あなたはすでにそれらが何であるかの基本的な定義を持っています。要するに、クラスT
にIEquatable<T>
を実装する場合、タイプEquals
のオブジェクトのT
メソッドは、オブジェクト自体(等価性がテストされているオブジェクト)かどうかを示します同じタイプの別のインスタンスT
と等しい。一方、IEqualityComparer<T>
は、通常T
のインスタンスのスコープ外で、T
の2つのインスタンスの等価性をテストするためのものです。
の目的は、最初は混乱する可能性があります。定義から、したがってIEquatable<T>
(クラスT
自体で定義されている)がそのオブジェクト/インスタンスの一意性を表す事実上の標準である必要があることは明らかです。 HashSet<T>
、Dictionary<T, U>
(GetHashCode
も考慮されます)、List<T>
などのContains
などはこれを利用します。 T
にIEqualityComparer<T>
を実装しても、上記の一般的なケースには役立ちません。その後、T
以外の他のクラスにIEquatable<T>
を実装する価値はほとんどありません。この:
class MyClass : IEquatable<T>
めったに意味がありません。
一方
class T : IEquatable<T>
{
//override ==, !=, GetHashCode and non generic Equals as well
public bool Equals(T other)
{
//....
}
}
それがどのように行われるべきかです。
IEqualityComparer<T>
は、等式のカスタム検証が必要な場合に役立ちますが、一般的な規則としてではありません。たとえば、Person
のクラスでは、ある時点で、年齢に基づいて2人の平等をテストする必要がある場合があります。その場合、次のことができます。
class Person
{
public int Age;
}
class AgeEqualityTester : IEqualityComparer<Person>
{
public bool Equals(Person x, Person y)
{
return x.Age == y.Age;
}
public int GetHashCode(Person obj)
{
return obj.Age.GetHashCode;
}
}
それらをテストするには、試してください
var people = new Person[] { new Person { age = 23 } };
Person p = new Person() { age = 23 };
print people.Contains(p); //false;
print people.Contains(p, new AgeEqualityTester()); //true
同様に、T
上のIEqualityComparer<T>
は意味をなしません。
class Person : IEqualityComparer<Person>
確かにこれは動作しますが、見た目が良くなく、ロジックを無効にします。
通常、必要なのはIEquatable<T>
です。また、理想的には、異なる基準に基づいて複数のIEquatable<T>
が可能ですが、IEqualityComparer<T>
を1つだけ持つことができます。
IEqualityComparer<T>
とIEquatable<T>
は、同等ではなく比較のために使用されるComparer<T>
とIComparable<T>
とまったく同じです。良いスレッド ここ 私が同じ答えを書いたところ:)
IEqualityComparerは、2つのオブジェクトの等価性が外部で実装されている場合に使用します。ソースを持たない2つのタイプの比較子を定義したい場合、または2つのものの等値が一部の限定されたコンテキストでのみ意味をなす場合。
IEquatableは、オブジェクト自体(等しいかどうかを比較するオブジェクト)が実装するためのものです。
2つのT
sを比較します。もう一方は、自分自身を他のT
sと比較できます。通常、一度に使用する必要があるのは一度に1つだけで、両方は必要ありません。