I have a struct representing a Measure in my program, which I want to be interchangeable with double.
I have implemented it, and everything seems to be working fine, except for one of my tests:
[Test]
public void TestMeasureDefaultConstructor()
{
Measure m = new Measure();
// These pass
Assert.That(m.Equals(0), Is.True);
Assert.That(0 == m, Is.True);
Assert.That((double) m, Is.EqualTo(0));
Assert.That((float) m, Is.EqualTo(0));
Assert.That(0, Is.EqualTo(m));
// The next two fail
Assert.That(m, Is.EqualTo(0.0));
Assert.That(0.0.Equals(m), Is.True);
}
Everything works up to the line with Is.EqualTo(0.0).
The two lines testing that 0.0 Equals m each fail as follows:
Message: Expected: 0.0d
But was: MyCode.Model.Measure
(obviously only the first fails, so I have to swap them round to prove this).
I have clearly implemented Equals for my Measure class sufficiently, but I can't work out how to extend double.Equals to make the last two work. I have done a lot of searches, but keep coming on how to implement Equals for my class rather than the other way round.
Here is my class, possibly overkill now after trying all sorts of ways to make it work:
/// <summary>
/// The Measure class encapsulates the unit of measurement.
/// </summary>
public struct Measure
{
#region Construction and destruction
public Measure(double v)
{
Value = v;
}
#endregion
#region Conversions
public static implicit operator Measure(double v)
{
return new Measure(v);
}
public static implicit operator double(Measure m)
{
return m.Value;
}
public static implicit operator float(Measure m)
{
return (float) m.Value;
}
#endregion
#region Properties
public double Value { get; set; }
#endregion
#region Equality
public static bool Equals(Measure a, Measure b)
{
// Constants.IsEqual checks abs(a - b) < Tolerance.
return Constants.IsEqual(a.Value, b.Value);
}
public static bool Equals(Measure a, object b)
{
return a.Equals(b);
}
public static bool Equals(object a, Measure b)
{
return b.Equals(a);
}
public bool Equals(Measure other)
{
return Equals(this, other);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
return false;
try
{
double d = Convert.ToDouble(obj);
return Equals(d);
}
catch (InvalidCastException)
{
return false;
}
catch (Exception e)
{
// Shouldn't get here!
Debug.Print("Unexpected exception in Measure.Equals: ", e);
if (System.Diagnostics.Debugger.IsAttached)
System.Diagnostics.Debugger.Break();
return false;
}
}
public static bool operator == (Measure x, Measure y)
{
return x.Equals(y);
}
public static bool operator != (Measure x, Measure y)
{
return !(x == y);
}
public override int GetHashCode()
{
return Value.GetHashCode();
}
#endregion
}
I have created a couple of extension methods:
public static class ExtensionMethods
{
public static bool Equals(this object a, Measure b)
{
return b.Equals(a);
}
public static bool Equals(this double a, Measure b)
{
return b.Equals(a);
}
}
I have put breakpoints on every Equals function, and they get hit during the passing tests, but none of these functions gets called for double.Equals so clearly the compiler doesn't think any of them are compatible.
Is this possible? If so, what am I missing, and how do I implement it?
Thanks in advance for any pointers.
Ian