iequalitycomparer とiequatable の違いは何ですか?
-
26-10-2019 - |
質問
シナリオを理解したいです IEqualityComparer<T>
と IEquatable<T>
使用すべきです。両方のMSDNドキュメントは非常によく似ています。
解決
IEqualityComparer<T>
タイプの2つのオブジェクトで比較を実行するオブジェクトのインターフェイスです T
.
IEquatable<T>
タイプのオブジェクト用です T
自分自身を他の人と比較できるように。
他のヒント
使用するかどうかを決定するとき IEquatable<T>
また IEqualityComparer<T>
, 、尋ねることができます:
の2つのインスタンスをテストする好ましい方法はありますか
T
平等のために、またはいくつかの等しく有効な方法がありますか?
の2つのインスタンスをテストする方法が1つしかない場合
T
平等の場合、またはいくつかの方法のいずれかが望ましい場合は、IEquatable<T>
正しい選択です:このインターフェイスはによってのみ実装されることになっていますT
それ自体、その1つのインスタンスT
自分自身を別のインスタンスと比較する方法についての内部知識がありますT
.一方、2つを比較する等しく合理的な方法がいくつかある場合
T
平等のためのsIEqualityComparer<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;
}
…
}
(上記)にリンクしたページには、このほぼ平等のテストにはいくつかの弱点があることを明示的に述べていることに注意してください。これはaです 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>
の上 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
s。もう一方は、それ自体を他のものと比較できます T
s。通常、両方ではなく、時間に1つだけを使用する必要があります。