Answers:
用途ReferenceEquals
:
Foo foo1 = null;
Foo foo2 = new Foo();
Assert.IsFalse(foo1 == foo2);
public static bool operator ==(Foo foo1, Foo foo2) {
if (object.ReferenceEquals(null, foo1))
return object.ReferenceEquals(null, foo2);
return foo1.Equals(foo2);
}
foo1.Equals(foo2)
举例来说,foo1 == foo2
如果我只想要,这意味着什么foo1.x == foo2.x && foo1.y == foo2.y
?这不是应答忽略的情况下foo1 != null
,但foo2 == null
?
if (foo1 is null) return foo2 is null;
在重载方法中强制转换为对象:
public static bool operator ==(Foo foo1, Foo foo2) {
if ((object) foo1 == null) return (object) foo2 == null;
return foo1.Equals(foo2);
}
(object)foo1 == null
或foo1 == (object)null
会进入内置的过载==(object, object)
,而不是用户定义的过载==(Foo, Foo)
。就像方法上的重载解析一样。
public static bool operator ==(Foo foo1, Foo foo2) {
if (ReferenceEquals(foo1, null)) return ReferenceEquals(foo2, null);
if (ReferenceEquals(foo2, null)) return false;
return foo1.field1 == foo2.field2;
}
如果我已经重写bool Equals(object obj)
并且想要运算符==
并Foo.Equals(object obj)
返回相同的答案,那么通常我会!=
像这样实现运算符:
public static bool operator ==(Foo foo1, Foo foo2) {
return object.Equals(foo1, foo2);
}
public static bool operator !=(Foo foo1, Foo foo2) {
return !object.Equals(foo1, foo2);
}
然后,操作员==
将在为我完成所有空检查之后,最终调用foo1.Equals(foo2)
我已被覆盖以进行实际检查(如果两者相等)。
Object.Equals(Object, Object)
并排的实现,Object.ReferenceEquals(Object, Object)
很明显,Object.Equals(Object, Object)
其他所有答案都按照开箱即用的方式完成了所有工作。为什么不使用它?
==
只要您想要的只是默认行为,操作符就没有意义。仅在需要实现自定义比较逻辑(即,除了引用相等性检查以外的其他内容)时才应重载。
==
情况下(问题暗示了这一点),我只是通过暗示不需要Object.Equals(Object, Object)
其他技巧(例如使用ReferenceEquals
或显式强制转换)来支持该答案(因此“为什么不使用它?”,“它”是Equals(Object, Object)
)。即使不相关,您的观点也是正确的,并且我会进一步讲:只有==
对于超载的对象,我们才能将其归类为“值对象”。
Object.Equals(Object, Object)
依次调用Object.Equals(Object),这是Foo可能会覆盖的虚拟方法。您已经在相等性检查中引入了虚拟调用的事实可能会影响编译器优化(例如,内联)这些调用的能力。在大多数情况下,这可能是微不足道的,但是在某些情况下,等于运算符的少量开销可能意味着循环或排序数据结构的巨大开销。
如果您使用的是C#7或更高版本,则可以使用空常量模式匹配:
public static bool operator==(Foo foo1, Foo foo2)
{
if (foo1 is null)
return foo2 is null;
return foo1.Equals(foo2);
}
这使您的代码比一个调用对象稍微整洁.ReferenceEquals(foo1,null)
public static bool operator==( Foo foo1, Foo foo2 ) => foo1?.Equals( foo2 ) ?? foo2 is null;
null
在这种情况下,实际上有一种更简单的检查方法:
if (foo is null)
而已!
此功能是C#7中引入的
我的方法是
(object)item == null
我依靠object
自己的平等运算符,不会出错。或自定义扩展方法(以及重载):
public static bool IsNull<T>(this T obj) where T : class
{
return (object)obj == null;
}
public static bool IsNull<T>(this T? obj) where T : struct
{
return !obj.HasValue;
}
或处理更多案件,可能是:
public static bool IsNull<T>(this T obj) where T : class
{
return (object)obj == null || obj == DBNull.Value;
}
约束可防止IsNull
出现值类型。现在就像打电话一样甜蜜
object obj = new object();
Guid? guid = null;
bool b = obj.IsNull(); // false
b = guid.IsNull(); // true
2.IsNull(); // error
这意味着我有一种始终如一/不易出错的样式来检查null。我还发现(object)item == null
它的速度比非常非常非常快Object.ReferenceEquals(item, null)
,但前提是这很重要(我目前正在研究必须对所有事物进行微优化的事物!)。
若要查看有关实现相等性检查的完整指南,请参阅什么是比较引用类型的两个实例的“最佳实践”?
静态Equals(Object, Object)
方法指示objA
和的两个对象是否objB
相等。它还使您能够测试其值是否null
相等的对象。它比较objA
和objB
平等,如下所示:
true
。此测试等效于调用该ReferenceEquals
方法。另外,如果objA
和objB
均为null
,则该方法返回true
。objA
或objB
是null
。如果是这样,则返回false
。如果两个对象不代表相同的对象引用,也不是null
,则它调用objA.Equals(objB)
并返回结果。这意味着如果objA
重写该Object.Equals(Object)
方法,则将调用此重写。。
public static bool operator ==(Foo objA, Foo objB) {
return Object.Equals(objA, objB);
}
向主要操作员回复更多有关如何与null进行比较的信息,此处将null重定向为重复项。
在这样做以支持Value Objects的情况下,我发现新的符号很方便,并且希望确保只有一个地方可以进行比较。还利用Object.Equals(A,B)简化了空检查。
这将重载==,!=,等于和GetHashCode
public static bool operator !=(ValueObject self, ValueObject other) => !Equals(self, other);
public static bool operator ==(ValueObject self, ValueObject other) => Equals(self, other);
public override bool Equals(object other) => Equals(other as ValueObject );
public bool Equals(ValueObject other) {
return !(other is null) &&
// Value comparisons
_value == other._value;
}
public override int GetHashCode() => _value.GetHashCode();
对于更复杂的对象,请在Equals和更丰富的GetHashCode中添加其他比较。
在操作者的重载一个常见的错误==是使用
(a == b)
,(a ==null)
或(b == null)
以检查引用相等。相反,这 导致对重载运算符==的调用,从而导致infinite loop
。使用ReferenceEquals
类型或将其强制转换为对象,以避免循环。
看看这个
// If both are null, or both are same instance, return true.
if (System.Object.ReferenceEquals(a, b))// using ReferenceEquals
{
return true;
}
// If one is null, but not both, return false.
if (((object)a == null) || ((object)b == null))// using casting the type to Object
{
return false;
}
您可以尝试使用对象属性并捕获生成的NullReferenceException。如果您尝试的属性是从Object继承或覆盖的,则此方法适用于任何类。
public static bool operator ==(Foo foo1, Foo foo2)
{
// check if the left parameter is null
bool LeftNull = false;
try { Type temp = a_left.GetType(); }
catch { LeftNull = true; }
// check if the right parameter is null
bool RightNull = false;
try { Type temp = a_right.GetType(); }
catch { RightNull = true; }
// null checking results
if (LeftNull && RightNull) return true;
else if (LeftNull || RightNull) return false;
else return foo1.field1 == foo2.field2;
}
Assert.IsFalse(foo2 == foo1);