我有一个类A
,该类拥有一个字符串属性,并覆盖Equals
以进行相等性测试。
public class A
{
public string Prop { get; }
public A(string val)
{
Prop = val;
}
public override bool Equals(object obj)
{
return obj is A arg && (Prop == arg.Prop);
}
public override int GetHashCode()
{
return base.GetHashCode();
}
}
我还有一个类B
,其属性为List<A>
:
public class B
{
public IReadOnlyList<A> Prop { get; }
public B(IReadOnlyList<A> val)
{
Prop = val;
}
public override bool Equals(object obj)
{
// ...
}
public override int GetHashCode()
{
return base.GetHashCode();
}
}
我想比较一下B实例的相等性和顺序。 如何通过不重写在A中编写的相同代码来在B中编写Equals方法? 有没有办法重用“等于”?
答案 0 :(得分:2)
更新:我的第一个版本假定为B
来自A
。
A.Equals
:如果未密封A
,则如果比较不同的类型,obj is A ...
可能返回假阳性。因此,更正的版本:
public override bool Equals(object obj)
{
return obj is A other
&& this.Prop == other.Prop
&& this.GetType() == other.GetType(); // not needed if A is sealed
}
A.GetHashCode
: base.GetHashCode
将为不同但相等的实例返回不同的哈希码,这是错误的。而是从自身属性派生哈希码。如果Prop
的行为类似于某个ID,则只需返回Prop.GetHashCode()
B.Equals
: public override bool Equals(object obj)
{
return obj is B other
&& this.Prop.SequenceEqual(other.Prop) // will re-use A.Equals
&& this.Prop.GetType() == other.Prop.GetType() // not needed if different IReadOnlyList types are ok
&& this.GetType() == other.GetType(); // not needed if B is sealed
}
B.GetHashCode
:您可以聚合A
实例的哈希码。在这里,我使用一个简单的XOR,但是如果相同的项目通常可以以不同的顺序出现,那么您可以想出一些更奇特的东西。
return Prop.Aggregate(0, (h, i) => h ^ i.GetHashCode());
答案 1 :(得分:1)
Linq包含一种比较集合的有用方法:SequenceEqual
public override bool Equals(object obj)
{
if (!(obj is B other))
{
return false;
}
if (this.Prop == null || other.Prop == null)
{
return false;
}
return this.Prop.SequenceEqual(other.Prop);
}
此外,当您覆盖Equals时,请实施IEquatable<T>
。
答案 2 :(得分:1)
通过使用Equals
方法(来自SequenceEquals
名称空间)可以为列表添加System.Linq
,这可以确保一个列表中的每个项目等于列表中相同索引处的项目。另一个列表。
您可能会考虑更改的一件事是GetHashCode
的实现。如果两个项目相等,则此方法应返回相同的数字(尽管不能保证具有相同哈希码的两个项目相等)。使用base.GetHashCode()
不符合此要求,因为在这种情况下base
是object
;根据{{3}},“用于引用类型的哈希码是通过调用基类的Object.GetHashCode方法来计算的,该方法基于对象的引用来计算哈希码” ,因此仅对象如果它们引用完全相同的对象,则返回相同的HashCode。
HashCode
应该基于用于确定相等性的相同属性,因此在这种情况下,我们要对类Prop.GetHashCode()
使用A
,并希望为Prop
中B
类的所有项目。
这是可以重构类的一种方法:
public class A : IEquatable<A>
{
public string Prop { get; }
public A(string val)
{
Prop = val;
}
public bool Equals(A other)
{
if (other == null) return false;
return Prop == other.Prop;
}
public override bool Equals(object obj)
{
return Equals(obj as A);
}
public override int GetHashCode()
{
return Prop.GetHashCode();
}
}
public class B : IEquatable<B>
{
public IReadOnlyList<A> Prop { get; }
public B(IReadOnlyList<A> val)
{
Prop = val;
}
public bool Equals(B other)
{
if (other == null) return false;
if (ReferenceEquals(this, other)) return true;
if (Prop == null) return other.Prop == null;
return other.Prop != null && Prop.SequenceEqual(other.Prop);
}
public override bool Equals(object obj)
{
return Equals(obj as B);
}
public override int GetHashCode()
{
return Prop?.Aggregate(17,
(current, item) => current * 17 + item?.GetHashCode() ?? 0)
?? 0;
}
}
答案 3 :(得分:0)
怎么样呢?
public override bool Equals(object obj)
{
if(!(obj is B))
{
return false;
}
var b = obj as B;
if(b.Prop.Count != this.Prop.Count)
{
return false;
}
for(var i =0; i < Prop.Count; i++)
{
if (!Prop.ElementAt(i).Equals(b.Prop.ElementAt(i)))
{
return false;
}
}
return true;
}