How do I check for nulls in an '==' operator overload without infinite recursion?

The following will cause infinite recursion on the == operator overload method

    Foo foo1 = null;
Foo foo2 = new Foo();
Assert.IsFalse(foo1 == foo2);


public static bool operator ==(Foo foo1, Foo foo2) {
if (foo1 == null) return foo2 == null;
return foo1.Equals(foo2);
}

How do I check for nulls?

8857 次浏览

在重载方法中强制转换为 object:

public static bool operator ==(Foo foo1, Foo foo2) {
if ((object) foo1 == null) return (object) foo2 == null;
return foo1.Equals(foo2);
}

使用 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);
}

试试 Object.ReferenceEquals(foo1, null)

无论如何,我不建议重载 ==操作符; 它应该用于比较引用,并使用 Equals进行“语义”比较。

使用 ReferenceEquals。从 MSDN 论坛:

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;
}

可以尝试使用对象属性并捕获结果 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;
}

If I have overridden bool Equals(object obj) and I want the operator == and Foo.Equals(object obj) to return the same value, I usually implement the != operator like this:

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)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 的一致的/不容易出错的风格。我还发现了 ABC0比 Object.ReferenceEquals(item, null)非常非常非常轻微地快,但只有在它重要的时候(我目前正在做一些事情,我必须对所有东西进行微优化!).

有关实现相等检查的完整指南,请参阅 比较引用类型的两个实例的“最佳实践”是什么?

操作符 = = 重载中的一个常见错误是使用 (a == b)(a ==null)(b == null)检查引用相等性。而是这个 导致对重载操作符 = = 的调用 ,从而导致 infinite loop。使用 ReferenceEquals或将类型强制转换为 Object,以避免 循环。

看看这个

// 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;
}

参考 Guidelines for Overloading Equals() and Operator ==

如果你使用的是 C # 7或更高版本,你可以使用 null 常量模式匹配:

public static bool operator==(Foo foo1, Foo foo2)
{
if (foo1 is null)
return foo2 is null;
return foo1.Equals(foo2);
}

这给出的代码比调用对象稍微整洁一些

静态 Equals(Object, Object)方法 指示两个对象 objAobjB是否相等。它还允许您测试其值为 null的对象是否相等。它对 objAobjB的平等性进行了如下比较:

  • 它确定两个对象是否表示相同的对象引用。如果是这样,该方法将返回 true。这个测试等效于调用 ReferenceEquals方法。此外,如果 objAobjB都是 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 进行比较重定向到这里作为一个复制。

在这样做是为了支持值对象的情况下,我发现新的表示法很方便,并且希望确保只有一个地方进行比较。同时利用 Object。等于(A,B)简化了空检查。

这将重载 = = 、 ! = 、 Equals 和 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();

For more complicated objects add additional comparisons in Equals and a richer GetHashCode.

在这种情况下,实际上有一种检查 null的简单方法:

if (foo is null)

That's it!

这个特性是在 C # 7中引入的

对于一个现代而简洁的句法:

public static bool operator ==(Foo x, Foo y)
{
return x is null ? y is null : x.Equals(y);
}


public static bool operator !=(Foo x, Foo y)
{
return x is null ? !(y is null) : !x.Equals(y);
}