我相信使用 .NET 的设计来获得像检查对象是否相等这样简单的东西有点棘手。
对于结构
1)实施IEquatable<T>
。它显着提高了性能。
2)既然你现在有自己的Equals
,覆盖GetHashCode
,并与各种相等检查覆盖保持一致object.Equals
。
3) 重载==
和!=
运算符不需要认真地完成,因为如果您无意地将一个结构与另一个等同于 a ,编译器会发出警告==
or !=
,但这样做是为了与Equals
方法保持一致。
public struct Entity : IEquatable<Entity>
{
public bool Equals(Entity other)
{
throw new NotImplementedException("Your equality check here...");
}
public override bool Equals(object obj)
{
if (obj == null || !(obj is Entity))
return false;
return Equals((Entity)obj);
}
public static bool operator ==(Entity e1, Entity e2)
{
return e1.Equals(e2);
}
public static bool operator !=(Entity e1, Entity e2)
{
return !(e1 == e2);
}
public override int GetHashCode()
{
throw new NotImplementedException("Your lightweight hashing algorithm, consistent with Equals method, here...");
}
}
上课
来自女士:
大多数引用类型不应该重载相等运算符,即使它们覆盖了 Equals。
对我来说==
,感觉就像价值平等,更像是Equals
方法的语法糖。写作a == b
比写作更直观a.Equals(b)
。我们很少需要检查引用相等性。在处理物理对象的逻辑表示的抽象级别中,这不是我们需要检查的。我认为具有不同的语义==
并且Equals
实际上可能会令人困惑。我相信它首先应该是==
为了价值平等和Equals
参考(或更好的名字,比如IsSameAs
)平等。我不想在这里认真对待 MS 指南,不仅因为它对我来说不自然,而且因为超载==
不会造成任何重大伤害。这不像不覆盖非泛型Equals
或者GetHashCode
可以反击,因为框架不会==
在任何地方使用,只有当我们自己使用它时。我从不重载==
!=
中获得的唯一真正好处是与我无法控制的整个框架的设计保持一致。这确实是一件大事,所以很遗憾我会坚持下去。
使用引用语义(可变对象)
1) 覆盖Equals
和GetHashCode
。
2)实施IEquatable<T>
不是必须的,但如果你有一个会很好。
public class Entity : IEquatable<Entity>
{
public bool Equals(Entity other)
{
if (ReferenceEquals(this, other))
return true;
if (ReferenceEquals(null, other))
return false;
//if your below implementation will involve objects of derived classes, then do a
//GetType == other.GetType comparison
throw new NotImplementedException("Your equality check here...");
}
public override bool Equals(object obj)
{
return Equals(obj as Entity);
}
public override int GetHashCode()
{
throw new NotImplementedException("Your lightweight hashing algorithm, consistent with Equals method, here...");
}
}
具有值语义(不可变对象)
这是棘手的部分。不小心很容易搞砸。。
1) 覆盖Equals
和GetHashCode
。
2)重载==
和!=
匹配Equals
。确保它适用于 nulls。
2)实施IEquatable<T>
不是必须的,但如果你有一个会很好。
public class Entity : IEquatable<Entity>
{
public bool Equals(Entity other)
{
if (ReferenceEquals(this, other))
return true;
if (ReferenceEquals(null, other))
return false;
//if your below implementation will involve objects of derived classes, then do a
//GetType == other.GetType comparison
throw new NotImplementedException("Your equality check here...");
}
public override bool Equals(object obj)
{
return Equals(obj as Entity);
}
public static bool operator ==(Entity e1, Entity e2)
{
if (ReferenceEquals(e1, null))
return ReferenceEquals(e2, null);
return e1.Equals(e2);
}
public static bool operator !=(Entity e1, Entity e2)
{
return !(e1 == e2);
}
public override int GetHashCode()
{
throw new NotImplementedException("Your lightweight hashing algorithm, consistent with Equals method, here...");
}
}
如果您的类可以被继承,请特别注意看看它应该如何处理,在这种情况下,您必须确定基类对象是否可以等于派生类对象。理想情况下,如果没有派生类的对象用于相等性检查,则基类实例可以等于派生类实例,在这种情况下,不需要在基类Type
的泛型中检查相等性。Equals
通常注意不要重复代码。我本可以制作一个通用抽象基类(IEqualizable<T>
或其他)作为模板,以便更轻松地重用,但遗憾的是在 C# 中这阻止了我从其他类派生。