Food
クラスは、Food
の別のインスタンスと等しいときはいつでもテストできるようにします。後でリストに対して使用し、そのList.Contains()
メソッドを使用します。 _IEquatable<Food>
_を実装するか、単にObject.Equals()
をオーバーライドする必要がありますか? MSDNから:
このメソッドは、オブジェクトのTのIEquatable.Equalsメソッドの実装(リスト内の値のタイプ)で定義されているように、デフォルトの等価比較子を使用して等価性を判断します。
だから私の次の質問は:.NET frameworkのどの関数/クラスがObject.Equals()
を利用するか?そもそもそれを使うべきですか?
主な理由はパフォーマンスです。ジェネリックが.NET 2.0で導入されたとき、List<T>
、Dictionary<K,V>
、HashSet<T>
などの一連のきちんとしたクラスを追加できました。これらの構造は、GetHashCode
およびEquals
を多用します。しかし、値型の場合、これにはボクシングが必要でした。 IEquatable<T>
を使用すると、構造体に厳密に型指定されたEquals
メソッドを実装できるため、ボクシングは不要です。したがって、ジェネリックコレクションで値型を使用すると、パフォーマンスが大幅に向上します。
参照型にはそれほどメリットはありませんが、IEquatable<T>
の実装により、System.Object
からのキャストを避けることができます。
Jared Parson's blog で述べたように、オブジェクトオーバーライドを実装する必要があります。
[〜#〜] msdn [〜#〜] によると:
_
IEquatable<T>
_を実装する場合は、Object.Equals(Object)
およびGetHashCode
の基本クラス実装もオーバーライドして、それらの動作が_IEquatable<T>.Equals
_メソッドの動作と一致するようにする必要があります。Object.Equals(Object)
をオーバーライドすると、オーバーライドされた実装は、クラスの静的Equals(System.Object, System.Object)
メソッドの呼び出しでも呼び出されます。これにより、Equals
メソッドのすべての呼び出しが一貫した結果を返すことが保証されます。
したがって、クラスの使用方法に応じて呼び出すことができることを除いて、2つの間に実際の機能的な違いはないようです。パフォーマンスの観点からは、ジェネリックバージョンを使用する方がよいのは、それに関連するボクシング/アンボクシングペナルティがないためです。
論理的な観点からは、インターフェイスを実装することをお勧めします。オブジェクトをオーバーライドしても、クラスが実際に赤道可能であることは誰にもわかりません。オーバーライドは、単に何もしないクラスまたは浅い実装です。インターフェイスを使用すると、「ねえ、これは等価チェックに有効です!」それはちょうど良いデザインです。
ジョシュが言ったことを実用的な例で拡張します。ジョシュへの+1-私は答えで同じことを書き込もうとしていました。
public abstract class EntityBase : IEquatable<EntityBase>
{
public EntityBase() { }
#region IEquatable<EntityBase> Members
public bool Equals(EntityBase other)
{
//Generic implementation of equality using reflection on derived class instance.
return true;
}
public override bool Equals(object obj)
{
return this.Equals(obj as EntityBase);
}
#endregion
}
public class Author : EntityBase
{
public Author() { }
}
public class Book : EntityBase
{
public Book() { }
}
このようにして、再利用可能なEquals()メソッドがあり、すべての派生クラスでそのまま使用できます。