Most of the answers here are good, but I'd like to suggest a slightly different approach.
First and foremost, units of measurement are values, and I think they should be treated as such by representing them as value types (i.e.
structs). There's a possibility that using a
struct may also increase performance slightly in some situations, but the value semantics and immutability involved are far more important than that.
So first, define a series of structs for each unit you will be handling, like so:
(Excuse the lack of newer features, I haven't used C# much since C# 4.0/4.5 was current version.)
public struct Metres : IEquatable<Metres>, IComparable<Metres>
public static readonly string Suffix = "m";
private double value;
public Metres(double value)
this.value = value;
public override int GetHashCode()
public override string ToString()
return this.value.ToString() + Suffix;
public override bool Equals(object obj)
if (obj == null)
if (obj is Metres)
public bool Equals(Metres other)
return this.value == other.value;
public int CompareTo(Metres other)
if (this > other)
if (this < other)
public static explicit operator Metres(double metres)
return new Metres(metres);
public static explicit operator double(Metres metres)
public static bool operator ==(Metres left, Metres right)
return left.value == right.value;
public static bool operator !=(Metres left, Metres right)
return left.value != right.value;
public static bool operator >(Metres left, Metres right)
return left.value > right.value;
public static bool operator >=(Metres left, Metres right)
return left.value >= right.value;
public static bool operator <(Metres left, Metres right)
return left.value < right.value;
public static bool operator <=(Metres left, Metres right)
return left.value <= right.value;
I suspect this would probably be a lot shorter using more modern features.
Essentially it's mainly just a wrapper around a
double, with a bit of custom behaviour.
IComparable as standard and added appropriate operator overloads.
Before I go further, a few caveats:
Firstly, as another answer pointed out,
doubles can be a bit difficult to test equality for, and there's other issues like infinity and NaN, so those operations aren't going to be perfect.
If you need to be that precise though, I'd suggest creating a helper class to handle
double comparisons and use that.
ToString here is not culture sensitive.
ToString will convert to a representation useful for a western culture, but not for other cultures, so if your program is going to be targetting other cultures you may need to rewrite
ToString or even come up with a more robust solution, perhaps using a specialised
Thirdly, I chose to make the conversion from
explicit conversion to be safe. You might find that in your situation it's acceptable or even desired to make that particular conversion
implicit. Conversely, the conversion from
Metres should always be a strong
And finallly, if you find that you need to be doing a lot of arithmetic with the units, you may wish to add some mathematical operators. If you do, you should make sure that they return the same kind of unit and only operate on either a unit and a double or a unit and the same unit. Personally I'd suggest making
- only working with two values of the unit because adding an arbitrary number to a unit doesn't make much sense (i.e.
unit + 5 doesn't make sense because the scale depends on the unit), whereas with
/ operating on an arbitrary number does make sense because it scales the value, (i.e.
unit * 2 makes sense - it doubles the amount, regardless of unit).
So, you do that for all the units that you're going to need (they should all look very similar), and then you create a helper class to handle the conversions:
public static class LengthConversions
private const double metreToCentimetreRatio = 1.0 / 100.0;
public static Centimetres ToCentimetres(Metres metres)
return new Centimetres((double)metres * metreToCentimetreRatio);
private const double centimetreToMetreRatio = 100.0 / 1.0;
public static Metres ToMetres(Centimetres centimetres)
return new Metres((double)centimetres * centimetreToMetreRatio);
Thus you have a single canonical representation of how to convert the units.
After that you should represent your person's
Height property with a canonical unit. I'd recommend using a metric unit rather than an imperial unit because metric units were designed with many useful mathematical properties in mind. Either metres or centimetres would be best for the human height range. (I'd lean more towards centimetres as it gives a nice balance of integer and fractional parts - not too big and not too small.)
Then whenever you have to convert the units you use the