HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMinor

Enums for measurement units, with possible circular dependency

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
unitswithmeasurementdependencypossiblecircularforenums

Problem

I have some enums that define measurement information, such as volume, mass, distance etc...

They are defined as such:

/// 
/// Units for measurement of area.
/// 
public enum Area
{
    /// 
    /// Meters squared.
    /// 
    M2 = 0,
    /// 
    /// Feet squared.
    /// 
    FT2
}


I have the need to display a short and long description for the units. A short description of meters in my case would be [m] and the long would simply be Meters. There are other larger enums for things like acceleration that define Kilometers per hour per second/[km/h/s].

What I'd done until now was use the DescriptionAttribute attribute to provide simply the short description:

/// 
/// Distance measurement units
/// 
public enum Distance
{
    ///  
    /// Meters.
    /// 
    [Description("[m]")]
    M = 0,        
    ...
}


That has worked for something that had a type of Distance. I've now got things that are defined as integer types that are actually a distance measurement:

public class MovementSnapshot
{
    /// 
    /// The total distance traveled, in meters.
    /// 
    public int TotalTravelDistance { get; private set; }

    /// 
    /// The current speed of the car. In KM/H
    /// 
    public int Speed { get; private set; }

    /// 
    /// The maximum speed achieved. In KM/H
    /// 
    public int MaxSpeed { get; private set; }
}


I defined a custom attribute to make it easier to display these properties when outputting them to file/screen etc... that looks like this:

```
///
/// Provides an interface for the display of Unit-type objects
///
public class UnitDisplayAttribute
: Attribute
{
///
/// The short display of the unit. Example: [N]
///
public string ShortDisplay { get; private set; }

///
/// Long long display of the unit. Example: Newtons
///
public string LongDisplay { get; private set; }

///
/// Construct the unit display attribute providing a short and long desc

Solution

I'm going to suggest a different approach entirely. I like OOP.

Create an interface.

public interface IUnitOfMeasure
{
    int Value { get; set; }
    string ShortDescription { get; }
    string LongDescription { get; }
}


And a Formatter Enum

public enum UnitOfMeasureFormat { Short, Long }


And then implement the interface, over riding and overloading the ToString() method.

public class Meters : IUnitOfMeasure
{
    public int Value { get; set; }
    public string ShortDescription { get { return "[m]"; }
    public string LongDescription { get { return "Meters"; }

    public override string ToString()
    {
        return this.Value + " " + this.ShortDescription;
    }

    public string ToString(UnitOfMeasureFormat format)
    {
        if (format == UnitOfMeasureFormat.Short)
        {
            return this.ToString();
        }

        return this.Value + " " + this.LongDescription;
    }
}


And now you can give your class' properties a "stronger" type.

public class MovementSnapshot
{
    public Meters TotalTravelDistance { get; private set; }


Simply calling the ToString() method when you need to display it.

myMovementSnapshot.TotalTravelDistance.ToString();


I didn't do it here, but at this point, you might want to start thinking about implementing unit converter methods as well as implementing the IEquatable and IComparable interfaces.

Code Snippets

public interface IUnitOfMeasure
{
    int Value { get; set; }
    string ShortDescription { get; }
    string LongDescription { get; }
}
public enum UnitOfMeasureFormat { Short, Long }
public class Meters : IUnitOfMeasure
{
    public int Value { get; set; }
    public string ShortDescription { get { return "[m]"; }
    public string LongDescription { get { return "Meters"; }

    public override string ToString()
    {
        return this.Value + " " + this.ShortDescription;
    }

    public string ToString(UnitOfMeasureFormat format)
    {
        if (format == UnitOfMeasureFormat.Short)
        {
            return this.ToString();
        }

        return this.Value + " " + this.LongDescription;
    }
}
public class MovementSnapshot
{
    public Meters TotalTravelDistance { get; private set; }
myMovementSnapshot.TotalTravelDistance.ToString();

Context

StackExchange Code Review Q#82686, answer score: 4

Revisions (0)

No revisions yet.