IEquatable 接口检查 null 时做什么
我使用以下代码在类中实现了 IEquatable 接口。
public bool Equals(ClauseBE other)
{
if (this._id == other._id)
{
return true;
}
return false;
}
public override bool Equals(Object obj)
{
if (obj == null)
{
return base.Equals(obj);
}
if (!(obj is ClauseBE))
{
throw new InvalidCastException("The 'obj' argument is not a ClauseBE object.");
}
return Equals(obj as ClauseBE);
}
public override int GetHashCode()
{
return this._id.GetHashCode();
}
public static bool operator ==(ClauseBE a, ClauseBE b)
{
// cast to object so we call the overloaded Equals function which appropriately checks when b is null.
return a.Equals(b as object);
}
public static bool operator !=(ClauseBE a, ClauseBE b)
{
// cast to object so we call the overloaded Equals function which appropriately checks when b is null.
return !a.Equals(b as object);
}
这段代码适用于大多数情况。 但是,以下检查会在相等运算符重载方法中引发异常,因为 a 为 null,因此没有 Equals 方法。
if(this.Clause != null)
{
}
解决这个问题的标准方法是什么?
编辑
我已经做到了这一点,但它看起来很麻烦。 我希望有一种更优雅的方式来实现这一点。
public static bool operator ==(ClauseBE a, ClauseBE b)
{
if (a as object == null && b as object == null)
{
return true;
}
if ((a as object == null && b as object != null)
|| (b as object == null && a as object != null))
{
return false;
}
// cast to object so we call the overloaded Equals function which appropriately checks when b is null.
return a.Equals(b as object);
}
public static bool operator !=(ClauseBE a, ClauseBE b)
{
if (a as object == null && b as object == null)
{
return false;
}
if((a as object == null && b as object != null)
|| (b as object == null && a as object != null))
{
return true;
}
// cast to object so we call the overloaded Equals function which appropriately checks when b is null.
return !a.Equals(b as object);
}
解决办法
谢谢大家。 我从大家那里得到了很多好的建议,我真的很感激。 这就是我最终决定的,它比我开始时要优雅得多。 除了运算符重载之外,所有代码都是相同的。
public static bool operator ==(ClauseBE a, ClauseBE b)
{
if (ReferenceEquals(a, null) && ReferenceEquals(b, null))
{
return true;
}
if (ReferenceEquals(a, null) || ReferenceEquals(b, null))
{
return false;
}
return a.Equals(b);
}
public static bool operator !=(ClauseBE a, ClauseBE b)
{
return !(a == b);
}
I have implemented the IEquatable interface in a class with the following code.
public bool Equals(ClauseBE other)
{
if (this._id == other._id)
{
return true;
}
return false;
}
public override bool Equals(Object obj)
{
if (obj == null)
{
return base.Equals(obj);
}
if (!(obj is ClauseBE))
{
throw new InvalidCastException("The 'obj' argument is not a ClauseBE object.");
}
return Equals(obj as ClauseBE);
}
public override int GetHashCode()
{
return this._id.GetHashCode();
}
public static bool operator ==(ClauseBE a, ClauseBE b)
{
// cast to object so we call the overloaded Equals function which appropriately checks when b is null.
return a.Equals(b as object);
}
public static bool operator !=(ClauseBE a, ClauseBE b)
{
// cast to object so we call the overloaded Equals function which appropriately checks when b is null.
return !a.Equals(b as object);
}
This code work very well for most all cases. However, the following check throws an exception in the equality operator overload method because a is null and therefore does not have a Equals method.
if(this.Clause != null)
{
}
What is the standard way to solve this issue?
EDIT
I have gone to this, but it seems pretty cumbersome. I was hoping there was a more elegant way to accomplish this.
public static bool operator ==(ClauseBE a, ClauseBE b)
{
if (a as object == null && b as object == null)
{
return true;
}
if ((a as object == null && b as object != null)
|| (b as object == null && a as object != null))
{
return false;
}
// cast to object so we call the overloaded Equals function which appropriately checks when b is null.
return a.Equals(b as object);
}
public static bool operator !=(ClauseBE a, ClauseBE b)
{
if (a as object == null && b as object == null)
{
return false;
}
if((a as object == null && b as object != null)
|| (b as object == null && a as object != null))
{
return true;
}
// cast to object so we call the overloaded Equals function which appropriately checks when b is null.
return !a.Equals(b as object);
}
Solution
Thanks all. I got a lot of good tips from everyone, I really appreciate it. This is what I finally settled on, it's a lot more elegant than what I had started with. All code is the same except operator overloads.
public static bool operator ==(ClauseBE a, ClauseBE b)
{
if (ReferenceEquals(a, null) && ReferenceEquals(b, null))
{
return true;
}
if (ReferenceEquals(a, null) || ReferenceEquals(b, null))
{
return false;
}
return a.Equals(b);
}
public static bool operator !=(ClauseBE a, ClauseBE b)
{
return !(a == b);
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
我总是发现使用 null 处理编写静态运算符更容易,并且让 Equals 重写以“this”作为参数之一调用重载运算符。
来自重载 Equals() 和运算符 == 的指南(C# 编程指南)
I've always found it easier to write the static operator with null handling, and have the Equals override call the overloaded operator with "this" as one of the parameters.
From Guidelines for Overloading Equals() and Operator == (C# Programming Guide)
这就是 ReSharper 创建相等运算符并实现
IEquatable
的方式,当然,我盲目地相信它;-)This is how ReSharper creates equality operators and implements
IEquatable<T>
, which I trust blindly, of course ;-)检查是否为 null 并返回 false。 如果操作数之一为 null,则等于应始终为 false;
Check for null and return false. Equals should always be false if one of the operands is null;
我认为这比在检查 null 之前转换为 Object 稍微麻烦一些:
I think this is a bit less cumbersome than casting to Object before checking for null:
其他答案为一般问题提供了很好的解决方案。
但是,您自己的代码可以简化为相对简单的解决方案...
首先,在您的
==
运算符的开头,您有这样的内容:这符合“工作太努力”的条件。
如果
ClauseBE
是引用类型,那么你只需要与null
进行比较——“as object
”是多余的; 同样,如果ClauseBE
是值类型,那么它永远不可能是null
。假设
ClauseBE
是引用类型(最有可能的情况),那么您可以简化为此 - 请注意,我们使用Object.Equals()
来避免无限递归和堆栈井喷。一种有用的快捷方式是使用
Object.ReferenceEquals()
- 它可以为您处理空值。所以你可以这样写:
这样做的好处是它还可以处理
a
和b
是同一个对象的情况。一旦通过了
Object.ReferenceEquals()
测试,您就会知道a
和b
是不同的。因此,您的下一个测试:
可以简化 - 因为您知道如果
a
为 null,则b
不能为 null,依此类推。如果此测试失败,那么您就知道
a
和b
不同,并且都不为 null。 现在是调用重写的Equals()
的好时机。Other answers give good solutions to the general problem.
However, your own code can be simplified into a relatively simple solution ...
Firstly, at the start of your
==
operator you have this:This qualifies as "working too hard".
If
ClauseBE
is a reference type, then you only need to compare withnull
- the "as object
" is redundant; equally, ifClauseBE
is a value type, then it can never benull
.Assuming that
ClauseBE
is a reference type (the most likely case), then you can simplify to this - note that we useObject.Equals()
to avoid infinite recursion and a stack blowout.One useful shortcut is to use
Object.ReferenceEquals()
- which handles nulls for you.So you could write this instead:
with the bonus that this also handles the case where
a
andb
are the same exact object.Once you get past the
Object.ReferenceEquals()
test, you know thata
andb
are different.So your next test:
can be simplified - since you know that if
a
is null,b
cannot be null, and so on.If this test fails, then you know that
a
andb
are different, and that neither is null. A good time to call your overriddenEquals()
.我使用了以下方法,它似乎对我很有效。 事实上,Resharper 建议采用这种方法。
I have used the following approach and it seemed to work well for me. Infact, Resharper suggests this approach.
我更喜欢在 Equals(T) 方法中执行所有比较逻辑,并将运算符重载中的“if this or that is null, else ...”留给框架。
覆盖运算符重载的唯一棘手的事情是您不能再在 Equals 实现中使用这些运算符,例如与
null
进行比较。 相反,object.ReferenceEquals
可以达到同样的效果。遵循 MSDN 中的 TwoDPoint 示例 重写 Equals() 和运算符 ==< 的指南/a> 文章,这是我在实现类型的值相等时生成的模式:
上面的形式是最安全的实现,因为它只是将字段相等性检查转发到框架,并且不需要知道字段是否重载相等运算符。 在您知道存在过载的情况下简化此操作是完全可以的:
您还可以替换
EqualityComparer
运算符中的调用会通过调用静态object.Equals
方法,当比较引用类型或装箱值类型无关紧要时:另请参阅 重写 GetHashCode 的最佳算法是什么? 用于实现
GetHashCode
。I prefer to perform all the comparison logic in the Equals(T) method, and leave the "if this or that is null, else ..." in operator overloads to the framework.
The only tricky thing about overriding operator overloads is that you can no longer use those operators in your Equals implementation, for example to compare with
null
. Instead,object.ReferenceEquals
can be used to achieve the same effect.Following the TwoDPoint example in the MSDN Guidelines for Overriding Equals() and Operator == article, this is the pattern I generate when implementing value equality for types:
The form above is the safest implementation, as it simply forwards the field equality checks to the framework and requires no knowledge of whether the fields overload the equality operators. It is perfectly fine to simplify this where you know the overload exists:
You can also replace the
EqualityComparer<T>
calls in the operator overloads with calls to the staticobject.Equals
method when comparing reference types, or when boxing value types does not matter:See also What is the best algorithm for an overridden GetHashCode? for implementing
GetHashCode
.