I run this open-source library cleverly named the Unit Class Library. It's purpose, like many others is to allow for more intelligent handling of units (rounding, conversion, etc.) Here is an example of the Library at work
Distance distance = new Distance(DistanceType.Inch, 3);
Area area = distance * distance;
Obviously the *
operator is overloaded in the Distance class like so:
public static Area operator *(Distance d1, Distance d2)
{
return new Area(d1, d2);
}
In attempting to make use of the library in a real application, I have come to the need to do some complex equations using these types and am currently having to reduce all of my units back to arbitrary doubles to do the math:
Let's pretend we are calculating Volumetric Flow Rate
(This is just an example. The equations in my real application end up with Distance ^ 5th and other strange units due to integrals and derivatives.)
Volume v = new Volume(VolumeType.CubicMeters, 10);
Time t = new Time(TimeType.Hours, 5);
double volumeAsDouble = v.CubicInches;
double timeAsDouble = t.Seconds;
double flowRateAsDouble = volume / time;
VolumetricFlowRate flowRate = new VolumetricFlowRate(VolumetricFlowRateType.InchesCubedPerSecond, flowRateAsDouble);
This is an unpleasant solution because it causes unnecessary conversions. This introduces unnecessary rounding errors. And I know that I can make an operator that handles this.
Tangent
If you look at the rest of the library, you will see that conversion from the passed in value to a different unit is delayed until it is needed. This ensures that if you will always get back the same value as you input as long as it is in the same Unit as it was given. Like so:
Distance distance = new Distance(DistanceType.Inch, 0.0000000012345)
double inches = distance.Inches; //inches will equal 0.0000000012345
// other libraries will convert the input value as soon as the distance object is created.
// That would likely cause the number to be rounded. This library does not convert until a different unit is requested.
end Tangent
I would like to be able to do this:
VolumetricFlowRate flowRate = volume / time;
Without having to edit the Volume class to include a new operator.
I could go into the appropriate places and add a new operator for each new combination that should return VolumetricFlowRate when it is added to the library, but this is tedious and breaks the open closed principle.
Does anyone have a suggestion of a solution that is cleanly extended with each new type, but without breaking the open closed principle?