Dictionary.ContainsKey()
の仕組みに関するMSDNドキュメントを読みましたが、実際に等値比較を行う方法を知りたいと思いましたか?基本的に、私は参照タイプ*をキーとするディクショナリを持っており、ContainsKey()
メソッドがその参照タイプの特定のプロパティをチェックして、キーが存在するかどうかを判断するための基礎として欲しいと思います。たとえば、Dictionary(MyObject, int)
があり、MyObject
に(int
の) "TypeID"というパブリックプロパティがある場合、ContainsKey(MyObject myObject)
を取得できますか?キーの1つにTypeID
がmyObject
と等しいかどうかを確認しますか? ==
演算子をオーバーロードできますか?
double Length
)を保持する「Duration」と呼ばれるオブジェクトです。 "Duration"は、私の音楽プログラムで特定のサウンドがどれだけ持続するかを示すために使用される基本タイプです。私はそこから、西洋の音楽の拍子記号などのより洗練されたタイミングの概念を組み込んだクラスを派生させていますが、それらの長さの点ですべて比較できるようにしたいと考えています。編集:提案されたように、私はオブジェクトにIEquitableを次のように実装しました:
public class Duration : IEquatable<Duration>
{
protected double _length;
/// <summary>
/// Gets or Sets the duration in Miliseconds.
/// </summary>
public virtual double Length
{
get
{
return _length;
}
set
{
_length = value;
}
}
// removed all the other code that as it was irrelevant
public override bool Equals(object obj)
{
Duration otherDuration = (Duration)obj;
if (otherDuration._length == _length)
{
return true;
}
else
{
return false
}
}
}
これで十分ですか?
編集:ここに更新された例のコードがあります。注:フィールドを保護されているものとして公開し、メンバーを公開する仮想プロパティもあるのは少し変だと思います。このスキームでは、何かがLength
をオーバーライドして、期待どおりに動作しないように__lenght
_を等価にする可能性があります。
_public class Duration : IEquatable<Duration>
{
protected double _length;
/// <summary>
/// Gets or Sets the duration in Miliseconds.
/// </summary>
public virtual double Length
{
get { return _length; }
set { _length = value; }
}
// removed all the other code that as it was irrelevant
public bool Equals(Duration other)
{
// First two lines are just optimizations
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return _length.Equals(other._length);
}
public override bool Equals(object obj)
{
// Again just optimization
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
// Actually check the type, should not throw exception from Equals override
if (obj.GetType() != this.GetType()) return false;
// Call the implementation from IEquatable
return Equals((Duration) obj);
}
public override int GetHashCode()
{
// Constant because equals tests mutable member.
// This will give poor hash performance, but will prevent bugs.
return 0;
}
}
_
辞書クラスで使用されるデフォルトの IEqualityComparer
については、 EqualityComparer.Default を参照してください。
クラスでGetHashCode
とEquals
を一般的にオーバーライドしたくない場合、またはそれができない場合。 Dictionaryコンストラクターのオーバーロード があり、使用する特定の IEqualityComparer
を指定できます。
これは実装するシンプルなインターフェースですが、GetHashCode
の規約を尊重するように注意する必要があります。そうしないと、予期しない動作が発生する可能性があります。
_public class MyObjectEqualityComparer : IEqualityComparer<MyObject>
{
public bool Equals(MyObject x, MyObject y)
{
return x.TypeID == y.TypeID;
}
public int GetHashCode(MyObject obj)
{
return obj.TypeID; //Already an int
}
}
_
使うだけ
_new Dictionary<MyObject, int>(new MyObjectEqualityComparer());
_
デフォルトのIEqualityComparerを使用する場合は、MyObjectEqualityComparerでほぼ同じメソッドを提供する必要があります。あなたはcanIEquatable を実装する場合、object.Equals()
のオーバーライドを回避できます=。ただし、これを行うと意外な動作が発生する可能性があるため、お勧めしません。 Equals
をオーバーライドすることをお勧めします。これにより、Equalsへのすべての呼び出しに対して一貫した動作が行われ、Equalsに適切に一致するハッシュが得られます。過去の開発者が_IEquatable.
_のみを実装したために発生した継承コードのバグを修正する必要がありました
内部的にはDictionary
はEqualityComparer
を使用します。まず、キーが IEquatable
を実装しているかどうかをチェックします。 keyがこのインターフェースを実装していない場合は、Equals
メソッドを呼び出します。