这是实现 Equals 和相等/不等运算符的良好/有效的习惯用法吗?
我在正确执行此操作时遇到了一些问题,因此我想询问是否有人对这是否是为自定义不可变类实现 Equals 方法和相等/不等运算符的有效方法有任何反馈。我的程序非常频繁地调用这些运算符,因此我想确保它们正确无误。
class MyObj
{
public static bool operator ==(MyObj a, MyObj b)
{
if (!object.ReferenceEquals(a, null))
return a.Equals(b);
else if (!object.ReferenceEquals(b, null))
return b.Equals(a);
else
// both are null
return true;
}
public static bool operator !=(MyObj a, MyObj b)
{
if (!object.ReferenceEquals(a, null))
return !a.Equals(b);
else if (!object.ReferenceEquals(b, null))
return !b.Equals(a);
else
// both are null
return false
}
public override bool Equals(object obj)
{
return this.Equals(obj as MyObj);
}
public bool Equals(MyObj obj)
{
if (object.ReferenceEquals(obj, null))
return false;
else
return (obj.FieldOne == this.FieldOne &&
obj.FieldTwo == this.FieldTwo && ...);
}
}
I have had a few problems getting this right, so I wanted to ask if anyone has any feedback on whether this is an efficient way to implement the Equals method and equality/inequality operators for a custom immutable class. These operators are called very frequently by my program, so I want to make sure I get them right.
class MyObj
{
public static bool operator ==(MyObj a, MyObj b)
{
if (!object.ReferenceEquals(a, null))
return a.Equals(b);
else if (!object.ReferenceEquals(b, null))
return b.Equals(a);
else
// both are null
return true;
}
public static bool operator !=(MyObj a, MyObj b)
{
if (!object.ReferenceEquals(a, null))
return !a.Equals(b);
else if (!object.ReferenceEquals(b, null))
return !b.Equals(a);
else
// both are null
return false
}
public override bool Equals(object obj)
{
return this.Equals(obj as MyObj);
}
public bool Equals(MyObj obj)
{
if (object.ReferenceEquals(obj, null))
return false;
else
return (obj.FieldOne == this.FieldOne &&
obj.FieldTwo == this.FieldTwo && ...);
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
我注意到的一些事情:
Equals
,所以您还应该重写GetHashCode
。Equals(MyObj)
方法是整个IEquatable
接口的有效实现,因此MyObj
确实应该实现该接口。这也将允许Dictionary<>
等直接利用您的Equals(MyObj)
方法,而不是通过Equals(object)
>。另外,我完全同意 Trillian 的替代实现,除了我会直接将
a != b
实现为!(a == b)
而不是!Equals( a,b)
。 (当然差异很小。)Some things I'm noticing:
Equals
, you should also overrideGetHashCode
.Equals(MyObj)
method is a valid implementation for the entireIEquatable<MyObj>
interface,MyObj
should indeed implement that interface. This will also allowDictionary<>
and such to directly take advantage of yourEquals(MyObj)
method, instead of going throughEquals(object)
.Also I completely agree with Trillian's alternative implementation, except I would've implemented
a != b
directly as!(a == b)
instead of!Equals(a, b)
. (Trivial difference of course.)基本上是的,但是有一个错误需要纠正。
Equals(object)
方法调用自身,而不是调用Equals(MyObj)
方法,从而导致永久循环。它应该是:或简单地:
另外,您可以将不等式运算符简化为:
Basically yes, but there is an error to correct.
The
Equals(object)
method calls itself instead of calling theEquals(MyObj)
method, causing an eternal loop. It should be:or simply:
Also, you can simplify the inequality operator to:
如果您正在寻求效率,我建议使用它而不是
object.ReferenceEquals(foo, null)
:这实际上是等效的,但避免了函数调用。
我还喜欢在所有覆盖
Equals
的类型中实现IEquatable
。对于引用类型,我然后将Equals(object)
转发到Equals(Foo)
。运算符重载可以这样简化:
不过,如果需要绝对效率,则可能值得在这些函数中重复一些代码以避免额外的函数调用,但与使用
( object)foo == null
而不是object.ReferenceEquals(foo, null)
,避免函数调用需要额外的代码来维护,因此小小的收益可能不值得。If you're looking for efficiency, I recommend using this instead of
object.ReferenceEquals(foo, null)
:This is effectively equivalent but avoids a function call.
I also like to implement
IEquatable<T>
in all my types that overrideEquals
. For reference types, I then forwardEquals(object)
toEquals(Foo)
.The operator overloads can be simplified as so:
If absolute efficiency is needed, though, it may be worth a little duplication of code in these functions to avoid the extra function calls, but unlike using
(object)foo == null
instead ofobject.ReferenceEquals(foo, null)
, avoiding the function call requires extra code to maintain, so the small gain may not be worth it.我更喜欢将所有“如果这是 null 则执行其他操作...”逻辑留给框架:
另请参阅 重写 GetHashCode 的最佳算法是什么? 用于实现
GetHashCode
。I prefer to leave all the "if this is null then do that else..." logic to the framework:
See also What is the best algorithm for an overridden GetHashCode? for implementing
GetHashCode
.我将以下代码片段用于引用类型,在我看来,它的重复更少并且感觉更干净。拥有静态“Equals”方法允许 .NET 语言在没有运算符重载的情况下比较您的实例,而无需在调用实例方法之前测试 null。如果您正在实现相等运算符,那么如果可以的话,最好使您的类不可变。
I use the following code snippet for reference types, which has less duplication and feels cleaner, in my opinion. Having a static "Equals" method allows .NET languages without operator overloading to compare your instances without having to test for null before calling the instance method. If you're implementing equality operators, it might also be best to make your class immutable, if you can.