简体   繁体   English

Dictionary.ContainsKey() - 它是如何工作的?

[英]Dictionary.ContainsKey() - How does it work?

I've read the MSDN documentation on how Dictionary.ContainsKey() works, but I was wondering how it actually makes the equality comparison? 我已经阅读了关于Dictionary.ContainsKey()如何工作的MSDN文档,但我想知道它是如何实际进行相等比较的? Basically, I have a dictionary keyed to a reference type* and I want the ContainsKey() method to check a certain property of that reference type as its basis for determining if the key exists or not. 基本上,我有一个键入引用类型*的字典,我希望ContainsKey()方法检查该引用类型的某个属性作为确定密钥是否存在的基础。 For example, if I had a Dictionary(MyObject, int) and MyObject has a public property (of int ) called "TypeID", could I get ContainsKey(MyObject myObject) to check to see if one of the keys has a TypeID that is equal to myObject ? 例如,如果我有一个Dictionary(MyObject, int)并且MyObject有一个名为“TypeID”的公共属性( int ),我可以获取ContainsKey(MyObject myObject)来检查其中一个键是否具有TypeID等于myObject Could I just overload the == operator? 我可以重载==运算符吗?

  • The reference type is an object called "Duration" which holds a value ( double Length ); 引用类型是一个名为“Duration”的对象,它保存一个值( double Length ); "Duration" is a base type used in my music program to denote how long a particular sound lasts. “持续时间”是我的音乐节目中使用的基本类型,表示特定声音持续多长时间。 I derive classes from it which incorporate more sophisticated timing concepts, like Western musical time signatures, but want all of them to be comparable in terms of their length. 我从中派生出类,其中包含更复杂的时序概念,如西方音乐时间签名,但希望它们在长度方面具有可比性。

EDIT: As suggested, I implemented IEquitable on my object like so: 编辑:正如所建议的,我在我的对象上实现了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
        }
    }

}

Is this all I need to do? 这就是我需要做的吗?

EDIT: here is code for your updated example. 编辑:这是您更新的示例的代码。 Note: I find it a little odd that you expose the field as protected, and also have a virtual property that exposes the member. 注意:我觉得将字段公开为受保护有点奇怪,并且还有一个公开该成员的虚拟属性。 Under this scheme something could override Length resulting in equality that looks at _lenght to not behave as expected. 在这种方案下,有些东西可以覆盖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;
    }
}

See EqualityComparer.Default for information on the default IEqualityComparer used by the Dictionary class. 有关Dictionary类使用的默认IEqualityComparer信息,请参见EqualityComparer.Default

If you do not want to generally override GetHashCode and Equals on the class, or if you are unable to. 如果您不希望通常在类上覆盖GetHashCodeEquals ,或者您不能。 There is an overload of the Dictionary constructor in which you can provide the specific IEqualityComparer to use. Dictionary构造函数有一个重载 ,您可以在其中提供要使用的特定IEqualityComparer

It is a simple interface to implement, but you do need to be careful that you respect the contract for GetHashCode or you can end up with unexpected behavior. 它是一个简单的实现接口,但您需要注意尊重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
    }
}

to use it just go 使用它只是去

new Dictionary<MyObject, int>(new MyObjectEqualityComparer());   

If you want to use the default IEqualityComparer you need to provide roughly the same methods on MyObjectEqualityComparer. 如果要使用默认的IEqualityComparer,则需要在MyObjectEqualityComparer上提供大致相同的方法。 You can avoid overriding object.Equals() if you implement IEquatable . 如果实现IEquatable, 可以避免覆盖object.Equals object.Equals() However I would strongly discourage it because doing so can create some surprising behavior. 但是我强烈反对它,因为这样做会产生一些令人惊讶的行为。 You are better of overriding Equals so that you have consistent behavior for all calls to Equals and have hashing that properly matches Equals. 您最好覆盖Equals以便对所有对Equals的调用具有一致的行为,并且具有与Equals正确匹配的散列。 I have had to fix a bug in inherited code caused by a past developer only implementing IEquatable. 我不得不修复由过去的开发人员实现IEquatable.导致的继承代码中的错误IEquatable.

Internally Dictionary uses EqualityComparer . 内部Dictionary使用EqualityComparer Firstly it will check whether key implements IEquatable . 首先,它将检查密钥是否实现IEquatable If key doesn't implement this interface, it will call Equals method. 如果key未实现此接口,则将调用Equals方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM