检查对象的 HashSet 是否相等
Checking equality with a HashSet of objects
我正在尝试将 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()
,但没有成功。
EqualityComparer<T>.Default
将查找实现 IEquatable<T>
的对象。否则,它将遵从 ObjectEqualityComparer
,它只是检查引用是否相等。这就是为什么在比较引用时您会看到 false 的原因。
您真正想要做的是明确实施 IEquatable<Location>
。请注意,您真的应该让您的属性不可变才能正常工作:
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<Location>
:
Console.WriteLine(EqualityComparer<Location>.Default.GetType())
您需要为集合创建比较器:
var setComparer = HashSet<Location>.CreateSetComparer();
return other.Variable.Equals(this.Variable) && setComparer.Equals(this.LocationList, other.LocationList);
我正在尝试将 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()
,但没有成功。
EqualityComparer<T>.Default
将查找实现 IEquatable<T>
的对象。否则,它将遵从 ObjectEqualityComparer
,它只是检查引用是否相等。这就是为什么在比较引用时您会看到 false 的原因。
您真正想要做的是明确实施 IEquatable<Location>
。请注意,您真的应该让您的属性不可变才能正常工作:
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<Location>
:
Console.WriteLine(EqualityComparer<Location>.Default.GetType())
您需要为集合创建比较器:
var setComparer = HashSet<Location>.CreateSetComparer();
return other.Variable.Equals(this.Variable) && setComparer.Equals(this.LocationList, other.LocationList);