代码之家  ›  专栏  ›  技术社区  ›  ashwnacharya

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

  •  4
  • ashwnacharya  · 技术社区  · 17 年前

    我有一个类,看起来像这样:

    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
        }
    

    2 回复  |  直到 15 年前
        1
  •  12
  •   Jon Skeet    17 年前

    根据您的评论,您还没有实现GetHashCode。我很惊讶这门课居然能用字典,除非你总是要求 相同的 您输入的密钥。我建议实现以下内容:

    public override int GetHashCode()
    {
        int hash = 17;
        hash = hash * 23 + UpperLimit.GetHashCode();
        hash = hash * 23 + LowerLimit.GetHashCode();
        return hash;
    }
    

    假定 Double.GetHashCode() 给出了NaN的一致值。当然,NaN有很多值,你 可能

    Equals 方法继承自 Object

    public override bool Equals(Object other)
    {
         return other != null && 
                other.GetType() == GetType() &&
                Equals((NumericalRange) other);
    }
    

    请注意,通过使用 as x.Equals(y) y.Equals(x) 如果有人从你那里衍生出另一个类。平等在继承方面变得棘手。

    你应该 将您的字段设置为私有,仅将其作为属性公开。如果这将被用作字典中的关键字,我 强烈地 建议你也把它们变成只读的。在字典中使用键时更改键的内容可能会导致以后“无法修复”。

        2
  •  7
  •   Guffa    17 年前

    GetHashCode方法的默认实现使用对象的引用,而不是对象中的值。为了使其工作,您必须使用与将数据放入字典时相同的对象实例。

    实施 GetHashCode

    public int GetHashCode() {
       return LowerLimit.GetHashCode() ^ UpperLimit.GetHashCode();
    }
    

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

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

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

    public int GetHashCode() {
       return (LowerLimit.GetHashCode() * 251) ^ UpperLimit.GetHashCode();
    }
    

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