I just wrote a piece of code that behaves quite differently then I would expect. It seems to tell me that I don't know everything yet about objects, so I humbly turn myself to the wisdom of my fellow colleagues of stack overflow to point me in the right direction.
This is the code that baffles 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 into the Console.WriteLine(...) which should not happen ...
Some things I have 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 remarks on this question seem to indicate that the class Identifier is important for this issue, 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);
}
}