Consider this struct:
public struct MyNumber
{
private readonly int _value;
public MyNumber(int myNumber)
{
_value = myNumber;
}
public int Value
{
get { return _value; }
}
public override bool Equals(object obj)
{
if (obj is MyNumber)
return this == (MyNumber) obj;
if (obj is int)
return Value == (int)obj;
return false;
}
public override string ToString()
{
return Value.ToString();
}
public static implicit operator int(MyNumber myNumber)
{
return myNumber.Value;
}
public static implicit operator MyNumber(int myNumber)
{
return new MyNumber(myNumber);
}
}
When I do this in a unit test:
Assert.AreEqual(new MyNumber(123), 123);
It's green.
But this test fails:
Assert.AreEqual(123, new MyNumber(123));
Why is this so? I'm guess it's because the int class determines the equality, whereas in the first case, my class determines it. But my class is implicitly convertible to int
, so shouldn't that help?
How can I make the Assert.AreEqual work in both ways? I'm using MSTest by the way.
Update
Implementing IEquatable<int>
or IComparable<int>
doesn't help.
The first assertion will invoke MyNumber.Equals
and you have implemented in a way where it will succeed if the argument to compare to is an Int32
and it is equal to value of MyNumber
.
The second assertion will invoke Int32.Equals
and it will fail because the argument to compare to is an MyNumber
which Int32
does not know about or understand.
You cannot make your second unit test succeed because you assert that an Int32
should be equal to your value. It cannot be because it is different. It is the code in Int32.Equals
that decides if the second value is equal. You have implemented some casting operators that you can unit test so these assertions should work:
Assert.AreEqual(123, (int) new MyNumber(123));
Assert.AreEqual((MyNumber) 123, new MyNumber(123));
Even though the casts are implemented implicit
they will not automatically be invoked by Assert.AreEquals
because this method expect two parameters of type Object
and you will have to invoke them explicitly as I did above.
Because of the special handling in your MyNumber.Equals
you now have a type that is not commutative with regards to equals, e.g. MyNumber(123) equals Int32(123)
is true but Int32(123) equals MyNumber(123)
is false. You should avoid that so I recommend that you remove the special case handling of ints in MyNumber.Equals
and instead rely on the implicit casts which will work for you most of the time. And when they do not you will have to make an explicit cast.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With