简体   繁体   中英

Creating a custom type that evaluates to double

I'm currently working on a class RoundedDouble . The aim of this class is to provide an alternative to the .Net double struct. It should work similarly to a double but that is rounded to a number of decimal places. At first we just wanted to have formatted numbers at the user interface level, but we're stuck with the requirement that we need to ensure that the value shown in the user interface is the value used in the calculation (limited precision of a double is accepted). That means a value that round to 2 decimals and was entered as 1.23456789 should evaluate to 1.23.

(Using a custom TypeConverter is something we have considered as an alternative, but we opted for the RoundedDouble as that would allow us with arithmetic that preserves the lowest precision similar to calculating with number and taking their significance/accuracy into account.)

Now I have implemented IEquatable<Double> for the RoundedDouble class and I've hit a snag for the following situation:

object roundedDoubleBoxedAsObject = new RoundedDouble(2, 1.23456789); //1st param is the number of decimal places
double expectedValue = 1.23;
Debug.Assert(Equals(roundedDoubleBoxedAsObject, expectedValue)); // Passes, as RoundedDouble.Equals(double) is called
Debug.Assert(Equals(expectedValue, roundedDoubleBoxedAsObject),
             "Rounded value should be considered equal."); // <-- Fails, because Double.Equals(object) is called!

I've already implemented an implicit conversion from RoundedDouble to Double that already covers a lot of problems. But when RoundedDouble is boxed as an object, the implicit conversion is circumvented.

Is this problem even solvable in C#? Or have I hit a limit in the programming language?

It seems that the problem of boxed comparison is already a challenge present in C# v4.0 as using System.Object.Equals(Object) will not work as you expected in cases like these:

double oneAsDouble = 1.0;
int oneAsInteger = 1;
Debug.Assert(oneAsDouble.Equals(oneAsInteger)); // Pass
Debug.Assert(oneAsInteger.Equals(oneAsDouble)); // Pass
Debug.Assert(Equals((object)oneAsDouble, (object)oneAsInteger)); // <-- Fails!
Debug.Assert(oneAsDouble.Equals((object)OneAsInteger)); // <-- Fails!
Debug.Assert(oneAsInteger.Equals((object)oneAsDouble)); // <-- Fails!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM