EqualityComparer .DEFAULT vs. T.Equals
-
27-10-2019 - |
質問
ジェネリックを持っているとします MyClass<T>
タイプの2つのオブジェクトを比較する必要があります <T>
. 。通常、私は次のようなことをします...
void DoSomething(T o1, T o2)
{
if(o1.Equals(o2))
{
...
}
}
今、私のと仮定してください MyClass<T>
カスタムの合格をサポートするコンストラクターがあります IEqualityComparer<T>
, 、 に似ている Dictionary<T>
. 。その場合、私はする必要があります...
private IEqualityComparer<T> _comparer;
public MyClass() {}
public MyClass(IEqualityComparer<T> comparer)
{
_comparer = comparer;
}
void DoSomething(T o1, T o2)
{
if((_comparer != null && _comparer.Equals(o1, o2)) || (o1.Equals(o2)))
{
...
}
}
この長いIFステートメントを削除するには、私が持っていることができればいいと思います _comparer
通常のコンストラクターが使用されている場合、「デフォルトの比較」にデフォルト。私はようなものを検索しました typeof(T).GetDefaultComparer()
しかし、そのようなものを見つけることができませんでした。
私は見つけました EqualityComparer<T>.Default
, 、それを使用できますか?そして、このスニペットになります...
public MyClass()
{
_comparer = EqualityComparer<T>.Default;
}
void DoSomething(T o1, T o2)
{
if(_comparer.Equals(o1, o2))
{
...
}
}
...使用と同じ結果を提供します o1.Equals(o2)
すべての可能な場合は?
(サイドノートとして、これは私が特別な一般的な制約を使用する必要があることを意味しますか <T>
?)
解決
同じであるべきですが、タイプの実装の詳細に依存するため、保証されていません T
.
説明:
制約なし T
, 、O1.Equals(O2)が呼び出します Object.Equals
, 、 もしそれでも T
道具 IEquatable<T>
.
EqualityComparer<T>.Default
ただし、使用します Object.Equals
のみ、場合 T
実装していません IEquatable<T>
. 。それであれば します そのインターフェイスを実装して、使用します IEquatable<T>.Equals
.
に限って T
の実装 Object.Equals
電話するだけです IEquatable<T>.Equals
結果は同じです。しかし、次の例では、結果は同じではありません。
public class MyObject : IEquatable<MyObject>
{
public int ID {get;set;}
public string Name {get;set;}
public override bool Equals(object o)
{
var other = o as MyObject;
return other == null ? false : other.ID == ID;
}
public bool Equals(MyObject o)
{
return o.Name == Name;
}
}
今、このようなクラスを実装することは意味がありません。しかし、の実装者が MyObject
単にオーバーライドするのを忘れました Object.Equals
.
結論:
使用 EqualityComparer<T>.Default
バギーオブジェクトをサポートする必要がないので、行くのに良い方法です!
他のヒント
デフォルトでは、クラスでオーバーライドされるまで、 Object.Equals(a,b)
/a.Equals(b)
参照ごとに比較を実行します。
比較するものは返されます EqualityComparer<T>.Default
に依存します T
. 。たとえば、if T : IEquatable<>
次に、適切です EqualityComparer<T>
作成されます。
null coaelescenseオペレーターを使用できますか?それが本当に重要な場合を短くするため
if ((_comparer ?? EqualityComparer<T>.Default).Equals(o1, o2))
{
}
はい、私は使用するのが賢明だと思います EqualityComparer<T>.Default
, 、の実装を使用するためです IEquatable<T>
タイプの場合 T
それを実装する、またはのオーバーライド Object.Equals
それ以外は。次のようにできます。
private IEqualityComparer<T> _comparer;
public IEqualityComparer<T> Comparer
{
get { return _comparer?? EqualityComparer<T>.Default;}
set { _comparer=value;}
}
public MyClass(IEqualityComparer<T> comparer)
{
_comparer = comparer;
}
void DoSomething(T o1, T o2)
{
if(Comparer.Equals(o1, o2))
{
...
}
}
それがまさにそれです Dictionary<>
また、BCLの他の一般的なコレクションは、オブジェクトの構築時に比較を指定しない場合に行います。これの利点はそれです EqualityComparer<T>.Default
正しい比較を返します IEquatable<T>
タイプ、ヌル可能なタイプ、および列挙。 Tがそれらのどれではない場合、古いコードが行っているような単純な比較を行います。