How can (xy! = Null && ((object) xy) == null) ever be true?

I just wrote a piece of code that behaves very differently than I expected. It seems to me that I do not yet know everything about objects, so I humbly turn to the wisdom of my fellow colleagues to point me in the right direction.

This is the code that puzzles me:

[Test]
public void TestMySanity()
{
    var oldSet = new Identifier[0];
    var newSet = new[]
    {
        new Identifier("1"),
        new Identifier("2")
    };

    var changes = uut.TrackChanges(oldSet, newSet, x => x).ToArray();

    ChangeRecord<Identifier> xx = changes.FirstOrDefault(x => x.New != null && x.Old != null);
    if (xx != null)
    {
        if (xx.Old != null && ((object) xx.Old) == null)
        {
            Console.WriteLine("How can something be not null and null at the same time?");
        }
        Assert.Fail("PS: this test expects a change record with Old = null and New = an Identifier");
    }
}

Just to be clear -> this code gets in Console.WriteLine(...), which should not happen ...

Some things I tried to get wiser:

Console.WriteLine("Is Object? " + (xx.Old is Object)); // = false
Console.WriteLine("Reference Equals? " + Object.ReferenceEquals(xx.Old, null)); // = true

try { Console.WriteLine(xx.Old.GetType().Name); }
catch (Exception ex)
{ Console.WriteLine("GetType() -> " + ex.Message);}
//Throws: Object reference not set to an instance of an object.

The comments on this question seem to indicate that the class identifier is important for this problem, so here it is:

public class Identifier : IComparable, IComparable<Identifier>, IEquatable<Identifier>
{
    //Var
    protected readonly IComparable Key;

    //Constructor
    public Identifier(IComparable key)
    {
        Key = key;
        if (key == null) throw new ArgumentNullException("key");
    }

    //Hashcode (Must be overridden when equals is overridden.)
    public override int GetHashCode()
    {
        return Key.GetHashCode();
    }

    public override string ToString()
    {
        return "[" + Key + "]";
    }

    //Compare
    public virtual int CompareTo(object obj)
    {
        return CompareTo((Identifier)obj);
    }

    public virtual int CompareTo(Identifier other)
    {
        if (other == null) return 1;
        return Key.CompareTo(other.Key);
    }

    //Equals
    public override bool Equals(object obj)
    {
        return Equals((obj as Identifier));
    }

    public virtual bool Equals(Identifier other)
    {
        if (ReferenceEquals(null, other)) return false;
        return Key.Equals(other.Key);
    }

    //Can be done because a Identifier is immutable
    public static bool operator ==(Identifier A, Identifier B)
    {
        if (ReferenceEquals(A, null)) return false;
        return A.Equals(B);
    }

    public static bool operator !=(Identifier A, Identifier B)
    {
        return !(A == B);
    }
}
+4
source share
2 answers

Error found:

public static bool operator ==(Identifier A, Identifier B)
{
    if (ReferenceEquals(A, null)) return false;
    return A.Equals(B);
}

, B - null? A == B true, , return false;

:

    if (ReferenceEquals(A, null)) return ReferenceEquals(B, null);
    return A.Equals(B);

, , , object ((object) xx.Old) == null, # object==, object.ReferenceEquals(A, B), -.

+7

== !=,

public class MyX {
  public MyY y {
    get;
    set;
  }
}

public class MyY {
  public static Boolean operator == (MyY left, Object right) {
    return true;
  }

  public static Boolean operator != (MyY left, Object right) {
    return true;
  }
}

....

var x = new MyX();

if (x.y != null && (((Object) x.y) == null)) {
  Console.Write("You've got it");
}

.

+2

All Articles