.NET units class, inches to millimeters

Tomas picture Tomas · May 17, 2011 · Viewed 19.8k times · Source

Does .NET has Units conversion class? I need to convert inches to millimeters and vise versa.

Answer

mattmc3 picture mattmc3 · Nov 8, 2012

I've dealt with this issue before. I recommend making two classes for distance. One that has the imperial measures and one that has the metric measures. Then, you can convert back and forth between them easily, with the obvious caveat that you lose precision when you do.

Here's an example of an imperial distance class, with inches as the base unit of measure.

public class ImperialDistance
{
    public static readonly ImperialDistance Inch = new ImperialDistance(1.0);
    public static readonly ImperialDistance Foot = new ImperialDistance(12.0);
    public static readonly ImperialDistance Yard = new ImperialDistance(36.0);
    public static readonly ImperialDistance Mile = new ImperialDistance(63360.0);

    private double _inches;

    public ImperialDistance(double inches)
    {
        _inches = inches;
    }

    public double ToInches()
    {
        return _inches;
    }

    public double ToFeet()
    {
        return _inches / Foot._inches;
    }

    public double ToYards()
    {
        return _inches / Yard._inches;
    }

    public double ToMiles()
    {
        return _inches / Mile._inches;
    }

    public MetricDistance ToMetricDistance()
    {
        return new MetricDistance(_inches * 0.0254);
    }

    public override int GetHashCode()
    {
        return _inches.GetHashCode();
    }

    public override bool Equals(object obj)
    {
        var o = obj as ImperialDistance;
        if (o == null) return false;
        return _inches.Equals(o._inches);
    }

    public static bool operator ==(ImperialDistance a, ImperialDistance b)
    {
        // If both are null, or both are same instance, return true
        if (ReferenceEquals(a, b)) return true;

        // if either one or the other are null, return false
        if (ReferenceEquals(a, null) || ReferenceEquals(b, null)) return false;

        // compare
        return a._inches == b._inches;
    }

    public static bool operator !=(ImperialDistance a, ImperialDistance b)
    {
        return !(a == b);
    }

    public static ImperialDistance operator +(ImperialDistance a, ImperialDistance b)
    {
        if (a == null) throw new ArgumentNullException();
        if (b == null) throw new ArgumentNullException();
        return new ImperialDistance(a._inches + b._inches);
    }

    public static ImperialDistance operator -(ImperialDistance a, ImperialDistance b)
    {
        if (a == null) throw new ArgumentNullException();
        if (b == null) throw new ArgumentNullException();
        return new ImperialDistance(a._inches - b._inches);
    }

    public static ImperialDistance operator *(ImperialDistance a, ImperialDistance b)
    {
        if (a == null) throw new ArgumentNullException();
        if (b == null) throw new ArgumentNullException();
        return new ImperialDistance(a._inches * b._inches);
    }

    public static ImperialDistance operator /(ImperialDistance a, ImperialDistance b)
    {
        if (a == null) throw new ArgumentNullException();
        if (b == null) throw new ArgumentNullException();
        return new ImperialDistance(a._inches / b._inches);
    }
}

And here's a metric class with meters as the base unit:

public class MetricDistance
{
    public static readonly MetricDistance Milimeter  = new MetricDistance(0.001);
    public static readonly MetricDistance Centimeter = new MetricDistance(0.01);
    public static readonly MetricDistance Decimeter  = new MetricDistance(0.1);
    public static readonly MetricDistance Meter      = new MetricDistance(1.0);
    public static readonly MetricDistance Decameter  = new MetricDistance(10.0);
    public static readonly MetricDistance Hectometer = new MetricDistance(100.0);
    public static readonly MetricDistance Kilometer  = new MetricDistance(1000.0);

    private double _meters;

    public MetricDistance(double meters)
    {
        _meters = meters;
    }

    public double ToMilimeters()
    {
        return _meters / Milimeter._meters;
    }

    public double ToCentimeters()
    {
        return _meters / Centimeter._meters;
    }

    public double ToDecimeters()
    {
        return _meters / Decimeter._meters;
    }

    public double ToMeters()
    {
        return _meters;
    }

    public double ToDecameters()
    {
        return _meters / Decameter._meters;
    }

    public double ToHectometers()
    {
        return _meters / Hectometer._meters;
    }

    public double ToKilometers()
    {
        return _meters / Kilometer._meters;
    }

    public ImperialDistance ToImperialDistance()
    {
        return new ImperialDistance(_meters * 39.3701);
    }

    public override int GetHashCode()
    {
        return _meters.GetHashCode();
    }

    public override bool Equals(object obj)
    {
        var o = obj as MetricDistance;
        if (o == null) return false;
        return _meters.Equals(o._meters);
    }

    public static bool operator ==(MetricDistance a, MetricDistance b)
    {
        // If both are null, or both are same instance, return true
        if (ReferenceEquals(a, b)) return true;

        // if either one or the other are null, return false
        if (ReferenceEquals(a, null) || ReferenceEquals(b, null)) return false;

        return a._meters == b._meters;
    }

    public static bool operator !=(MetricDistance a, MetricDistance b)
    {
        return !(a == b);
    }

    public static MetricDistance operator +(MetricDistance a, MetricDistance b)
    {
        if (a == null) throw new ArgumentNullException("a");
        if (b == null) throw new ArgumentNullException("b");
        return new MetricDistance(a._meters + b._meters);
    }

    public static MetricDistance operator -(MetricDistance a, MetricDistance b)
    {
        if (a == null) throw new ArgumentNullException("a");
        if (b == null) throw new ArgumentNullException("b");
        return new MetricDistance(a._meters - b._meters);
    }

    public static MetricDistance operator *(MetricDistance a, MetricDistance b)
    {
        if (a == null) throw new ArgumentNullException("a");
        if (b == null) throw new ArgumentNullException("b");
        return new MetricDistance(a._meters * b._meters);
    }

    public static MetricDistance operator /(MetricDistance a, MetricDistance b)
    {
        if (a == null) throw new ArgumentNullException("a");
        if (b == null) throw new ArgumentNullException("b");
        return new MetricDistance(a._meters / b._meters);
    }
}

And here's a test method that exemplifies the usage.

[TestMethod]
public void _5in_Equals_12_7cm()
{
    var inches = new ImperialDistance(5);
    var cms = new MetricDistance(MetricDistance.Centimeter.ToMeters() * 12.7);
    var calcCentimeters = Math.Round(inches.ToMetricDistance().ToCentimeters(), 2, MidpointRounding.AwayFromZero);
    var calcInches = Math.Round(cms.ToImperialDistance().ToInches(), 2, MidpointRounding.AwayFromZero);

    Assert.AreEqual(cms.ToCentimeters(), 12.7);
    Assert.AreEqual(calcCentimeters, 12.7);
    Assert.AreEqual(inches.ToInches(), 5);
    Assert.AreEqual(calcInches, 5);
}

You can also add extension methods:

public static MetricDistance Centimeters(this Int32 that)
{
    return new MetricDistance(MetricDistance.Centimeter.ToMeters() * that);
}

[TestMethod]
public void _100cm_plus_300cm_equals_400cm()
{
    Assert.AreEqual(100.Centimeters() + 300.Centimeters(), 400.Centimeters());
}

You can use this simple strategy for weights, temperatures, liquid measures, etc.