【问题标题】:Checking equality with a HashSet of objects用对象的 HashSet 检查相等性
【发布时间】:2015-12-15 09:03:31
【问题描述】:

我正在尝试将Definition 类型的两个哈希集与EqualityComparer<T>.Default.Equals(value, oldValue) 进行比较。 Definition 定义如下

public class Definition
{
    public string Variable { get; set; }
    public HashSet<Location> LocationList { get; set; }

    public override bool Equals(object obj)
    {
        Definition other = obj as Definition;
        return other.Variable.Equals(this.Variable) && other.LocationList!= null &&this.LocationList != null
            && other.LocationList.Count == this.LocationList.Count
            && other.LocationList == this.LocationList;
    }

    public override int GetHashCode()
    {
        return this.Variable.GetHashCode() ^ this.LocationList.Count.GetHashCode();// ^ this.LocationList.GetHashCode();
    }
}

public class Location
{
    public int Line { get; set; }
    public int Column { get; set; }
    public int Position { get; set; }
    public string CodeTab { get; set; }
    public Location(int line, int col, int pos, string tab)
    {
        Line = line;
        Column = col;
        Position = pos;
        CodeTab = tab;
    }
    public override bool Equals(object obj)
    {
        Location other = obj as Location;
        return this.CodeTab == other.CodeTab
            && this.Position == other.Position
            && this.Column == other.Column
            && this.Line == other.Line;
    }
    public override int GetHashCode()
    {
        return this.CodeTab.GetHashCode() ^ this.Position.GetHashCode() 
            ^ this.Column.GetHashCode() ^ this.Line.GetHashCode();
    }
}

不知何故,对于类似的集合,结果返回为false,尽管所有信息都保持不变。唯一的区别是某些元素的位置是互换的,但我知道HashSet 在比较时不会保留或检查顺序。谁能告诉我这里出了什么问题?

PS:我也尝试取消注释this.LocationList.GetHashCode(),但没有成功。

【问题讨论】:

  • 这是HashSet&lt;Location&gt; 不是HashSet&lt;Definition&gt;,但您声明要比较“定义的两个哈希集”。所以要么你的问题问错了,要么你的代码做了不同的事情。
  • valueoldValueDefinition 类型。

标签: c# hashset iequalitycomparer


【解决方案1】:

您需要为集合创建一个比较器:

var setComparer = HashSet<Location>.CreateSetComparer();
return other.Variable.Equals(this.Variable) && setComparer.Equals(this.LocationList, other.LocationList);

【讨论】:

    【解决方案2】:

    EqualityComparer&lt;T&gt;.Default 将寻找实现IEquatable&lt;T&gt; 的对象。否则,它将遵循ObjectEqualityComparer,它只是检查引用是否相等。这就是为什么您在比较引用时看到错误的原因。

    您真正想要做的是显式实现IEquatable&lt;Location&gt;。请注意,您确实应该使您的属性不可变以使其正常工作:

    public class Location : IEquatable<Location>
    {       
        public Location(int line, int col, int pos, string tab)
        {
            Line = line;
            Column = col;
            Position = pos;
            CodeTab = tab;
        }
    
        public int Line { get; private set; }
        public int Column { get; private set; }
        public int Position { get; private set; }
        public string CodeTab { get; private set; }
    
        public bool Equals(Location other)
        {
            if (ReferenceEquals(null, other)) return false;
            if (ReferenceEquals(this, other)) return true;
            return string.Equals(CodeTab, other.CodeTab) && Column == other.Column && Line == other.Line && Position == other.Position;
        }
    
        public override bool Equals(object obj)
        {
            if (ReferenceEquals(null, obj)) return false;
            if (ReferenceEquals(this, obj)) return true;
            if (obj.GetType() != this.GetType()) return false;
            return Equals((Location) obj);
        }
    
        public static bool operator ==(Location left, Location right)
        {
            return Equals(left, right);
        }
    
        public static bool operator !=(Location left, Location right)
        {
            return !Equals(left, right);
        }
    
        public override int GetHashCode()
        {
            unchecked
            {
                var hashCode = (CodeTab != null ? CodeTab.GetHashCode() : 0);
                hashCode = (hashCode*397) ^ Column;
                hashCode = (hashCode*397) ^ Line;
                hashCode = (hashCode*397) ^ Position;
                return hashCode;
            }
        }
    }
    

    现在,如果您查看由Default 创建的类型EqualityComparer,您将看到GenericEqualityComparer&lt;Location&gt;

    Console.WriteLine(EqualityComparer<Location>.Default.GetType())
    

    【讨论】:

      猜你喜欢
      • 2013-03-21
      • 1970-01-01
      • 2012-06-23
      • 2015-07-19
      • 2016-04-18
      • 2015-01-18
      • 1970-01-01
      • 2019-06-26
      • 2016-05-23
      相关资源
      最近更新 更多