24

どのように機能するかについてのMSDNドキュメントを読みましたが、Dictionary.ContainsKey()実際にどのように等式比較を行うのか疑問に思いました。基本的に、私は参照型*にキー設定された辞書を持っておりContainsKey()、キーが存在するかどうかを判断するための基礎として、その参照型の特定のプロパティをチェックするメソッドが必要です。たとえば、がDictionary(MyObject, int)あり、 「TypeID」というMyObjectパブリックプロパティ(の)がある場合、キーの1つに等しいaがあるかどうかを確認できますか?演算子をオーバーロードできますか?intContainsKey(MyObject myObject)TypeIDmyObject==

  • double Length参照型は、値( )を保持する「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
        }
    }

}

これが私がする必要があるすべてですか?

4

2 に答える 2

12

編集:更新された例のコードは次のとおりです。注:フィールドを保護されたものとして公開し、メンバーを公開する仮想プロパティも持っているのは少し奇妙だと思います。このスキームでは、何かがオーバーライドされて、期待どおりに動作しないように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;
    }
}

Dictionary クラスで使用されるデフォルトについては、EqualityComparer.Defaultを参照してください。IEqualityComparer

一般的にクラスでオーバーライドGetHashCodeしたくない場合、またはできない場合。使用する特定のものを提供できるDictionary コンストラクターEqualsのオーバーロードがあります。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 でほぼ同じメソッドを提供する必要があります。IEquatableを実装すると、オーバーライドを回避できます。ただし、そうすると驚くべき動作が発生する可能性があるため、強くお勧めしません。Equals へのすべての呼び出しに対して一貫した動作が得られ、Equals と適切に一致するハッシュが得られるように、オーバーライドする方が適切です。過去の開発者が実装のみを行ったために発生した、継承されたコードのバグを修正する必要がありました。object.Equals()EqualsIEquatable.

于 2012-11-07T02:13:25.883 に答える
9

を内部的にDictionary使用しEqualityComparerます。まず、キーが実装されているかどうかを確認しますIEquatable。key がこのインターフェースを実装していない場合、Equalsメソッドを呼び出します。

于 2012-11-07T01:53:21.150 に答える