写一个好的C#Equals方法
有没有人有编写一个像样的equals方法的模板?我记得在有效的Java中,在处理子类时,在处理equals方面存在一些问题写一个好的C#Equals方法,c#,C#,有没有人有编写一个像样的equals方法的模板?我记得在有效的Java中,在处理子类时,在处理equals方面存在一些问题 我没有这本书,我记不起这是不是一个实用的建议——那么如何编写一个可靠的健壮的equals方法实现呢?我通常会这样做: public struct EmailAddress : IEquatable<EmailAddress> { public override bool Equals(object obj) { return ob
我没有这本书,我记不起这是不是一个实用的建议——那么如何编写一个可靠的健壮的equals方法实现呢?我通常会这样做:
public struct EmailAddress : IEquatable<EmailAddress>
{
public override bool Equals(object obj)
{
return obj != null && obj.GetType() == typeof(EmailAddress) && Equals((EmailAddress)obj);
}
public bool Equals(EmailAddress other)
{
return this.LocalPart == other.LocalPart && this.Domain == other.Domain;
}
}
public结构电子邮件地址:IEquatable
{
公共覆盖布尔等于(对象对象对象)
{
返回obj!=null&&obj.GetType()==typeof(EmailAddress)&&Equals((EmailAddress)obj);
}
公共bool Equals(电子邮件地址其他)
{
返回this.LocalPart==other.LocalPart&&this.Domain==other.Domain;
}
}
您可能已经这样做了,但是您是否查阅了MSDN关于实现Equals()
的文章
一个“good”equals方法是一个比较类的唯一部分的方法,同时忽略了对唯一性没有贡献的部分。所以,如果你有一个id是唯一的类,你可以用它来建立平等,而不考虑任何其他属性。不过,通常您也需要一些时间戳值。请查看MSDN。好的equals方法的属性:
- 对称性:对于两个参考,a和b,a等于(b)当且仅当b等于(a)
- 自反性:对于所有非空引用,a等于(a)
- 及物性:如果a.等于(b)和b.等于(c),那么a.等于(c)
可能是墙外的建议:但是,首先考虑不要重写<代码>等于。正如您所提到的,基本上平等的本质不适合子类化。但是,在.NET API中,几乎所有使用相等的地方(例如字典、哈希集)都允许传入
IEqualityComparer
。让一个不同的对象负责平等使生活更加灵活:你可以使用不同的对象来决定使用哪种标准
实现IEqualityComparer
要简单得多-您仍然需要检查空值,但不需要担心类型是否合适,或者Equals
是否会被进一步覆盖
另一种使正常的
Equals
工作更顺利的方法是在大部分情况下完全避免继承-我不记得上次在我的代码中重写Equals
并允许派生类是什么时候真正有意义的sealed
FTW:)如果您厌倦了为此编写大量样板文件,可以尝试使用一个基类来实现它
public abstract class ValueObject<T> : IEquatable<T>
where T : ValueObject<T>
{
protected abstract IEnumerable<object> Reflect();
public override bool Equals(Object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (obj.GetType() != GetType()) return false;
return Equals(obj as T);
}
public bool Equals(T other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return Reflect().SequenceEqual(other.Reflect());
}
public override int GetHashCode()
{
return Reflect().Aggregate(36, (hashCode, value) => value == null ?
hashCode : hashCode ^ value.GetHashCode());
}
public override string ToString()
{
return "{ " + Reflect().Aggregate((l, r) => l + ", " + r) + " }";
}
}
公共抽象类ValueObject:IEquatable
其中T:ValueObject
{
受保护的抽象IEnumerable Reflect();
公共覆盖布尔等于(对象对象对象)
{
if(ReferenceEquals(null,obj))返回false;
if(obj.GetType()!=GetType())返回false;
返回等于(obj为T);
}
公共布尔等于(T其他)
{
if(ReferenceEquals(null,other))返回false;
if(ReferenceEquals(this,other))返回true;
返回Reflect().SequenceEqual(其他.Reflect());
}
公共覆盖int GetHashCode()
{
return Reflect().Aggregate(36,(hashCode,value)=>value==null?
hashCode:hashCode^value.GetHashCode());
}
公共重写字符串ToString()
{
返回“{”+Reflect().Aggregate((l,r)=>l+”,“+r)+“}”;
}
}
现在要创建一个类似类的值,只需说:
public class Person : ValueObject<Person>
{
public int Age { get; set; }
public string Name { get; set; }
protected override IEnumerable<object> Reflect()
{
return new object[] { Age, Name };
}
}
公共类人物:ValueObject
{
公共整数{get;set;}
公共字符串名称{get;set;}
受保护的覆盖IEnumerable Reflect()
{
返回新对象[]{Age,Name};
}
}
在Reflect
override中,您返回一系列需要有助于实现相等的值
不幸的是,这种方法无助于声明运算符==
,因为必须在派生类型上专门声明它。公共类Person
{
公共字符串名称{get;set;}
public int Age { get; set; }
public override bool Equals(object obj)
{
var objAsPerson = obj as Person;
if (obj == null)
{
return false;
}
if (this.Name != objAsPerson.Name)
{
return false;
}
if (this.Age != objAsPerson.Age)
{
return false;
}
return true;
}
}