The result of calling IEquatable <T> .Equals (T obj) when is == null and obj == null?

What should IEquatable<T>.Equals(T obj) do when this == null and obj == null ?

1) This code is generated by the F # compiler when implementing IEquatable<T> . You can see that it returns true when both objects are null :

  public sealed override bool Equals (T obj)
     {
         if (this == null)
         {
             return obj == null;
         }
         if (obj == null)
         {
             return false;
         }

         // Code when both this and obj are not null.
     }

2) . Similar code can be found in the question " in the implementation of IEquatable is link checking ) or in the question" Is there a complete link to the implementation of IEquatable? ". This code returns false when both objects are null .

  public sealed override bool Equals (T obj)
     {
         if (obj == null)
         {
             return false;
         }

         // Code when obj is not null.
     }

3) . The final option is to say that the behavior of the method is undefined when this == null .

+7
source share
7 answers

leppie is right. To give a detailed account of his answer (and to confirm his suspicion that F # does not guarantee this != null) : discriminatory associations can be marked with the attribute [<CompilationRepresentation(CompilationRepresentationFlags.UseNullAsTrueValue)>] , which allows us to consider cases as null. Option<'T> is that type. The None case is represented by zero at runtime. (None : option<int>).Equals(None) syntactically correct. Here is a fun example:

 [<CompilationRepresentation(CompilationRepresentationFlags.UseNullAsTrueValue)>] type Maybe<'T> = | Just of 'T | Nothing [<CompilationRepresentation(CompilationRepresentationFlags.Instance)>] member this.ThisIsNull() = match this with Nothing -> true | _ -> false 

Decompiling ThisIsNull Using Reflector Shows

 public bool ThisIsNull() { return (this == null); } 

And the result:

 Nothing.ThisIsNull() //true 
+4
source

The reason F # does this (I suspect) is to optimize empty lists as null .

By adding this check, it allows you to easily invoke the instance method on the null instance.

See my blog post after a while.

In C #, this does not matter.

To answer the question:

It should return true , since both instances are null and are considered equal.

+2
source

If this is null, the code cannot be called, so this case does not need to be considered (in C #, in any case, there are cases when languages ​​allow the null object to have a dereferenced method, although it is obvious if it internally examines any of its non-existent fields, this will be an error. Consider:

 return x.Equals(y); 

If x is null, we cannot even call Equals to null check for counting.

Therefore, we only need to consider:

 public bool Equals(T obj) { if(obj == null) return false; //logic defining equality here. } 

If the probability that both objects are equal to zero arises when we study them from a static redefinition of the == operator or from an implementation of IEqualityComparer<T> :

 public bool Equals(T x, T y) { if(x == null) return y == null; if(y == null) return false; //logic defining equality here. } 

Note that here is a useful shortcut, if equality can be long to define (for example, comparing long strings), then we can take advantage of the fact that identity entails equality - this is something that always coincides with itself, even Ayn Rand could figure it out;) There are also algorithms that make comparing an element with itself quite common, which makes this shortcut quite appropriate. In this case, identity comparison already includes checking that both values ​​are zero, so we leave this again:

 public bool Equals(T x, T y) { if(ReferenceEquals(x, y)) return true; if(x == null || y == null) return false; //logic defining equality here. } 
+1
source

For most methods, I assume undefined behavior when called with this==null . This is because most programmers write their code under the assumption that this!=null , which is guaranteed by the C # specification if the calling code is written in C #.

So that every sensible caller x.Equals(y) needs to know for sure that x not null , or add a manual null check.

In most cases, I would not call Equals at all, but instead used EqualityComparer<T>.Default .

+1
source

I would definitely go with option 1:

  if (this == null) { return obj == null; } if (obj == null) { return false; } 

The null object is always zero.

0
source
0
source

If this == null, you will get a runtime exception that calls Equals () for this object.

0
source

All Articles