IEqualityComparer<T>
とを使用する必要があるシナリオを理解したいと思いIEquatable<T>
ます。両方のMSDNドキュメントは非常によく似ています。
5 に答える
IEqualityComparer<T>
タイプの2つのオブジェクトで比較を実行するオブジェクトのインターフェイスですT
。
IEquatable<T>
T
同じタイプのオブジェクトと比較できるように、タイプのオブジェクト用です。
IEquatable<T>
使用するかどうかを決定するときIEqualityComparer<T>
、次のように尋ねることができます。
T
の2つのインスタンスが等しいかどうかをテストする好ましい方法はありますか、それとも同じように有効な方法がいくつかありますか?
T
2つのインスタンスの同等性をテストする方法が1つしかない場合、またはいくつかの方法の1つが望ましい場合IEquatable<T>
は、正しい選択です。このインターフェイスはT
単独で実装されることになっているため、の1つのインスタンスにT
は次の内部知識があります。の別のインスタンスと自分自身を比較する方法T
。一方、2つ
T
のsを同等に比較するための同等に合理的な方法がいくつかある場合は、IEqualityComparer<T>
より適切に思われます。このインターフェイスは、T
それ自体ではなく、他の「外部」クラスによって実装されることを意図しています。したがって、2つのインスタンスのT
同等性をテストする場合、同等性についての内部的な理解がないため、特定の要件に従ってテストを実行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<>
、同等性テストを行う他の意味のある方法はないように思われるため、両方のタイプを実装する必要があります。
ここでの問題は、浮動小数点数の等式の比較が、微小な丸め誤差のために期待どおりに機能しない可能性があることです。ほぼ等しい浮動小数点数を比較する方法はいくつかあり、それぞれに特定の利点とトレードオフがあり、どちらの方法が適切かを自分で選択できるようにしたい場合があります。
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>
実装であるため、目的に十分でない場合は、単に交換することができます。
あなたはすでにそれらが何であるかの基本的な定義を持っています。つまり、IEquatable<T>
クラスT
に実装する場合Equals
、型のオブジェクトのメソッドはT
、オブジェクト自体(等しいかどうかがテストされているもの)が同じ型の別のインスタンスと等しいかどうかを示しますT
。一方、は、のインスタンスの範囲外である、IEqualityComparer<T>
の任意の2つのインスタンスの同等性をテストするためのものです。T
T
それらが何のためにあるかについては、最初は混乱する可能性があります。定義から、したがってIEquatable<T>
(クラスT
自体で定義されている)は、そのオブジェクト/インスタンスの一意性を表すための事実上の標準である必要があることは明らかです。HashSet<T>
、Dictionary<T, U>
(考慮GetHashCode
も上書きされます)、Contains
などList<T>
でこれを利用します。IEqualityComparer<T>
onを実装しT
ても、上記の一般的なケースには役立ちません。IEquatable<T>
その後、。以外の他のクラスに実装する価値はほとんどありません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
同様IEqualityComparer<T>
に、上T
は意味がありません。
class Person : IEqualityComparer<Person>
確かにこれは機能しますが、見た目が良くなく、ロジックを打ち負かします。
通常、必要なのはですIEquatable<T>
。また、理想的には1つしか持てませんが、さまざまな基準に基づいてIEquatable<T>
複数が可能です。IEqualityComparer<T>
IEqualityComparer<T>
とは、とIEquatable<T>
完全に類似してComparer<T>
おりIComparable<T>
、同等にするのではなく、比較の目的で使用されます。私が同じ答えを書いたここの良いスレッド:)
IEqualityComparerは、2つのオブジェクトの同等性が外部で実装されている場合に使用します。たとえば、ソースがない2つのタイプの比較子を定義する場合や、2つのオブジェクト間の同等性が限られたコンテキストでのみ意味をなす場合に使用します。
IEquatableは、オブジェクト自体(同等性について比較されているオブジェクト)を実装するためのものです。
1つは2つのを比較しT
ます。他の人は自分自身を他T
の人と比較することができます。通常、一度に使用する必要があるのは1つだけで、両方を使用する必要はありません。