tags:

views:

178

answers:

3

Does anyone know of any examples or code that shows a class or struct that can be used for distance like the DateTime struct? I need to be able to add, subtract, and display the data in feet and inches and using conversion methods just gets messy. A class or struct would be perfect, but I came across nothing in my searches.

+8  A: 

Use a struct, but make it immutable (all properties are get-only).

Properties should include at least:

  • TotalFeet
  • TotalInches

Methods should include at least:

  • FromFeet (static)
  • FromInches (static)

Declare the private backing field as:

private readonly double _meters;

Edit: Maybe something like this.

public struct Distance : IEquatable<Distance>, IComparable<Distance>
{
    private static readonly double MetersPerKilometer = 1000.0;
    private static readonly double CentimetersPerMeter = 100.0;
    private static readonly double CentimetersPerInch = 2.54;
    private static readonly double InchesPerFoot = 12.0;
    private static readonly double FeetPerYard = 3.0;
    private static readonly double FeetPerMeter = CentimetersPerMeter / (CentimetersPerInch * InchesPerFoot);
    private static readonly double InchesPerMeter = CentimetersPerMeter / CentimetersPerInch;

    private readonly double _meters;

    public Distance(double meters)
    {
        this._meters = meters;
    }

    public double TotalKilometers
    {
        get
        {
            return _meters / MetersPerKilometer;
        }
    }

    public double TotalMeters
    {
        get
        {
            return _meters;
        }
    }

    public double TotalCentimeters
    {
        get
        {
            return _meters * CentimetersPerMeter;
        }
    }

    public double TotalYards
    {
        get
        {
            return _meters * FeetPerMeter / FeetPerYard;
        }
    }

    public double TotalFeet
    {
        get
        {
            return _meters * FeetPerMeter;
        }
    }

    public double TotalInches
    {
        get
        {
            return _meters * InchesPerMeter;
        }
    }

    public static Distance FromKilometers(double value)
    {
        return new Distance(value * MetersPerKilometer);
    }

    public static Distance FromMeters(double value)
    {
        return new Distance(value);
    }

    public static Distance FromCentimeters(double value)
    {
        return new Distance(value / CentimetersPerMeter);
    }

    public static Distance FromYards(double value)
    {
        return new Distance(value * FeetPerYard / FeetPerMeter);
    }

    public static Distance FromFeet(double value)
    {
        return new Distance(value / FeetPerMeter);
    }

    public static Distance FromInches(double value)
    {
        return new Distance(value / InchesPerMeter);
    }

    public static Distance operator +(Distance a, Distance b)
    {
        return new Distance(a._meters + b._meters);
    }

    public static Distance operator -(Distance a, Distance b)
    {
        return new Distance(a._meters - b._meters);
    }

    public static Distance operator -(Distance a)
    {
        return new Distance(-a._meters);
    }

    public override bool Equals(object obj)
    {
        if (!(obj is Distance))
            return false;

        return Equals((Distance)obj);
    }

    public bool Equals(Distance other)
    {
        return this._meters == other._meters;
    }

    public int CompareTo(Distance other)
    {
        return this._meters.CompareTo(other._meters);
    }

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

    public override string ToString()
    {
        return string.Format("{0}[m]", TotalMeters);
    }
}
280Z28
Thanks. I'm looking for a library (or class definition) of this already done with all the happy adding and subtracting and tostring functions. I could write it, but if someone else has done it, why not use that.
Wili
LOL! I love the private backing field name ;) +1 for saving this in meters!
Reed Copsey
Sweet! You wouldn't happen to have one that does temperature too, would you? :) Out of curiosity, won't immutability add overhead when adding and subtracting, ala string concatenation?
Jeremy Seghi
Very nice. I don't know why we just don't use the metric system. It makes a lot more sense.
Wili
@Jeremy Seghi: Since it's a struct, constructing a new instance consists of initializing a value on the stack. Since the object is backed by a double and the operators do not involve conversions, the overhead of immutability is effectively near zero. I wrote this struct just for this post - you could create a similar one for temperature (if you do, note the use of static fields for the clean unit conversions).
280Z28
You should use `decimal` instead of `double`. Otherwise you'll (sooner or later) discover that `Distance.FromMeters(1/3) + Distance.FromMeters(1/3) != Distance.FromMeters(2/3)`!
Ronald
@Ronald: `decimal` has more precision than `double`, but it is still not a full-precision type. This is like complaining that `TimeSpan` is inadequate because the resolution is at most one tick. On a side note, in your particular example the integer division truncates and you'll always have equality.
280Z28
@280Z28: True, but as `TimeSpan` has a resolution of one tick, why not limit `Distance` to, for example, one centimetre? This should take care of any rounding/conversion loss when comparing distances. As distance has a large scale, using base units and storing the value as an integer, may be a good solution.
Ronald
@Ronald: If it was stored as an integer, a much better choice is storing it as a `long` in Ångströms, which offers integral representation of both customary and SI units, with a range of over ±922337 km (about the distance to the moon and back).
280Z28
+7  A: 

I've written self-contained unit converter classes before, but I don't know of a good one for .NET that is public.

That being said, it's quite easy to write - Just make a struct that can be constructed from inches or feet, and convertable to both.

public struct Distance
{
     private Distance(int inches)
     {
         this.totalInches = inches;
     }

     private int totalInches;

     public int Inches { get { return this.totalInches % 12; }  }

     public int Feet { get { return this.totalInches / 12; } }

     public static Distance FromInches(int inches)
     {
          return new Distance(inches);
     }

     public static Distance FromFeet(int feet)
     {
          return new Distance(feet * 12);
     }

     public static Distance FromFeetAndInches(int feet, int inches)
     {
          return new Distance(feet * 12 + inches);
     }

}
Reed Copsey
Dan Puzey
Metrics, metrics, we dont need no stinking metrics.
pm100
Resolution would be vastly improved if you used double instead of int.
ebpower
Only if you need fractions of an inch - otherwise, it would just slow things down. The OP just specified inches + feet.
Reed Copsey
A: 
public class Length
{
    public double Inches { get; set; }

    public double Feet
    {
        get { return Inches / 12.0; }
        set { Inches = value * 12.0; }
    }

    public double Meters
    {
        get { return Inches / 39.3700787; }
        set { Inches = value * 39.3700787; }
    }

    public double Furlongs
    {
        get { return Feet / 660.0; }
        set { Feet = value * 660.0; }
    }

    public double Miles
    {
        get { return Furlongs / 8.0; }
        set { Furlongs = value * 8.0; }
    }
}
ebpower
Your miles setter should be "set { Furlongs = value * 8.0; }"...
Reed Copsey
Good catch - thanks.
ebpower