关于字典<T,T>的问题

ash*_*rya 4 .net c# dictionary

我有一个看起来像这样的课:

public class NumericalRange:IEquatable<NumericalRange>
    {
        public double LowerLimit;
        public double UpperLimit;

        public NumericalRange(double lower, double upper)
        {
            LowerLimit = lower;
            UpperLimit = upper;
        }

        public bool DoesLieInRange(double n)
        {
            if (LowerLimit <= n && n <= UpperLimit)
                return true;
            else
                return false;
        }

        #region IEquatable<NumericalRange> Members

        public bool Equals(NumericalRange other)
        {
            if (Double.IsNaN(this.LowerLimit)&& Double.IsNaN(other.LowerLimit))
            {
                if (Double.IsNaN(this.UpperLimit)  && Double.IsNaN(other.UpperLimit))
                {
                    return true;
                }
            }

            if (this.LowerLimit == other.LowerLimit && this.UpperLimit == other.UpperLimit)
                return true;
            return false;
        }

        #endregion
    }
Run Code Online (Sandbox Code Playgroud)

该类包含一个数值范围的值.此类还应该能够保持默认范围,其中LowerLimit和UpperLimit都等于Double.NaN.

现在这个课进入了一个词典

字典适用于'非NaN'数值范围值,但当Key为{NaN,NaN} NumericalRange对象时,字典会抛出KeyNotFoundException.

我究竟做错了什么?我还有其他任何接口要实现吗?

Jon*_*eet 12

根据您的评论,您尚未实现GetHashCode.我很惊讶这个课程在字典中完全有效,除非你总是要求你输入相同的密钥.我建议实现类似的东西:

public override int GetHashCode()
{
    int hash = 17;
    hash = hash * 23 + UpperLimit.GetHashCode();
    hash = hash * 23 + LowerLimit.GetHashCode();
    return hash;
}
Run Code Online (Sandbox Code Playgroud)

假定 Double.GetHashCode()为NaN提供了一致的值.当然,NaN有很多值,你可能想要特殊情况来确保它们都给出相同的哈希值.

您还应该覆盖EqualsObject以下方法继承的方法:

public override bool Equals(Object other)
{
     return other != null && 
            other.GetType() == GetType() &&
            Equals((NumericalRange) other);
}
Run Code Online (Sandbox Code Playgroud)

请注意,as如果您密封课程,可以使用类型检查更有效.否则你会在两者之间产生有趣的不对称x.Equals(y),y.Equals(x)如果有人从你那里派出另一个类.继承会使平等变得棘手.

应该将您的字段设为私有,仅将其作为属性公开.如果这将被用作字典中的键,我强烈建议您也将它们作为只读字符串.在字典中使用密钥时更改密钥的内容可能会导致密钥在以后"不可用".

  • Jon F&%$ ing ing Skeet !! 这就像在梵蒂冈寻求方向并得到教皇的回答!http://preview.tinyurl.com/5va9gs (4认同)

Guf*_*ffa 7

GetHashCode方法的默认实现使用对象的引用而不是对象中的值.您必须使用与用于将数据放入字典中的对象相同的实例才能使用该实例.

它的实现GetHashCode只是从它的数据成员的哈希码创建一个代码:

public int GetHashCode() {
   return LowerLimit.GetHashCode() ^ UpperLimit.GetHashCode();
}
Run Code Online (Sandbox Code Playgroud)

(这与Point结构使用的实现相同.)

对于任何给定参数值始终返回相同哈希码的方法的任何实现在字典中使用时都有效.只返回所有值的相同哈希码实际上也可以工作,但随后字典的性能变差(查找键变为O(n)操作而不是O(1)操作.为了获得最佳性能,方法应该在范围内均匀分布哈希码.

如果您的数据存在严重偏差,则上述实施可能无法提供最佳性能.例如,如果您有很多范围,其中下限和上限相同,则它们都将获得哈希码零.在这种情况下,这样的事情可能会更好:

public int GetHashCode() {
   return (LowerLimit.GetHashCode() * 251) ^ UpperLimit.GetHashCode();
}
Run Code Online (Sandbox Code Playgroud)

您应该考虑使该类不可变,即将其属性设置为只读,并仅在构造函数中设置它们.如果更改对象在Dictionary中的属性,它的哈希码将会更改,您将无法再访问该对象.

  • 我知道如何正确回答这种感觉,并且由于"The Skeet"+1的伟大而黯然失色 (5认同)