I have the need to implements a solution requiring the use of a value that can be in one of two measurement units (for now): Liters or Cubic Centimeters. We need to be able to convert the value between the units. I.e. if we change from Liters to Cubic Centimeters, our value changes from 1.0 to 1000.0 and visa versa.
We are looking at two approaches to accomplish this and I am wondering what thoughts anyone has for the pro's & con's of each:
1. Develop a single struct (value type), LengthUnit, that has a enumeration property identifying the current units. When the unit property is changed, we apply the conversion and change the value. We would accept a value from the enumeration in the constructor and expose static Liter and CubicCentimeter methods for quick creation.
2. Develop two (2) structs, Liter and CubicCentimeter, and a custom TypeConverter assigned to both. The TypeConverter would use the ILengthUnit interface (implemented by both) to access the necessary conversion factor and perform the conversion.
The first seems consistent with the way that Microsoft has implemented units in the framework, such as System.Web.UI.WebControls.Unit, but MS doesn't perform conversions between the units (i.e. no conversion from 'pixel' to 'point').
I like the second because it allows us to treat each unit like its own type and we derive the benefits from that; however, we see the possibility of expanding this in the future to add things like Gallon, FluidOunce, Milliliter, etc. and each of these would have to be implemented as their own struct. The TypeConverter would not have to be changed if we used a common interface to expose what it needs to do the job, so to speak. But, we could end up with a significant number of objects.
The other issue that I have with the second approach is code-reuse. Since we can't inherit our unit objects from a common struct, implementation code would have to be repeated in each case whereas option #1, because it is all in one struct, we only have to do it once.
Thoughts?
Thanks for the feedback. It sounds like the second approach is the right one. We'll have to deal with the short-comings using struct's instead of classes (so we're dealing with value types). But, I agree that having the conversion aspect handled in a TypeConverter class isolates that responsibility and makes the model more flexible.
And, since the framework makes use of the TypeConverter natively, we can switch between types by simply casting (I think) or by exposing, like you said, a static method that takes advantage of the TypeConverter to do the work.
I'll have to look into some helper classes for some of the methods that are in common to obtain better code reuse than is available by nature with structs but otherwise, I think its a good approach. Thanks again.
SonOfPirate:And, since the framework makes use of the TypeConverter natively, we can switch between types by simply casting (I think) or by exposing, like you said, a static method that takes advantage of the TypeConverter to do the work.
Yea, I misunderstood what you were saying previously but have come back to the same conclusion when evaluating how to implement a Parse function that would accept both the magnitude and units of measure in the string. If we have different types, then the parser has to possess all of the knowledge about the acceptable string portions in order to instantiate the correct type; where as going with a single type allows us to encapsulate this within the single Parse method. This really put the brakes on having a separate type for each unit of measure.
We were looking to be able to have the following:
CubicCentimer ccVal = new CubicCentimeter(1000.0);
Liter literVal = (Liter)ccVal; // literVal = 1.0 L;
But, I think in order to have the full range of behaviors we want, we'll have to settle for:
Volume ccVal = Volume.CubicCentimeter(1000.0);
Volume literVal = ccVal.ConvertTo(Liter);
Which is not a problem, just have to have a separate enumeration to track the possible units of measure as we originally thought would be the case.
Copyright (c) Marimer LLC