65.9K
CodeProject is changing. Read more.
Home

A C# Temperature Struct

starIconstarIconemptyStarIconemptyStarIconemptyStarIcon

2.00/5 (2 votes)

Jan 6, 2012

CPOL
viewsIcon

16070

A temperature struct in C#

Microsoft loves using temperature in .NET examples. See here and here.

So, I decided to combine them all into a nice structure that implements IFormattable, IComparable, IEquatable<t>, etc. That way, they don't have to keep rewriting it themselves.

The code also gives some good examples on operator overloading. Have fun.

using System;
using System.Globalization;

/// <summary>
/// Options for temperature measurement units.
/// </summary>
public enum TemperatureUnit
{
    /// <summary>
    /// The SI base unit of thermodynamic temperature,
    /// equal in magnitude to the degree Celsius.
    /// </summary>
    Kelvin,

    /// <summary>
    /// A scale of temperature on which water freezes
    /// at 0° and boils at 100° under standard conditions.
    /// </summary>
    Celsius,

    /// <summary>
    /// A scale of temperature on which water freezes at 32°
    /// and boils at 212° under standard conditions.
    /// </summary>
    Fahrenheit
}

/// <summary>
/// A temperature value.
/// </summary>
public struct Temperature : IFormattable, IComparable, 
       IComparable<Temperature>, IEquatable<Temperature>
{
    private double _Kelvin;

    /// <summary>
    /// Creates a new temperature with the specified value in Kelvin.
    /// </summary>
    /// <param name="kelvin">The value of the temperature.</param>
    public Temperature(double kelvin) : this() { _Kelvin = kelvin; }

    /// <summary>
    /// Creates a new temperature with the specified value in the
    /// specified unit of measurement.
    /// </summary>
    /// <param name="temperature">The value of the temperature.</param>
    /// <param name="unit">The unit of measurement that defines how
    /// the <paramref name="temperature"/> value is used.</param>
    public Temperature(double temperature, TemperatureUnit unit)
        : this()
    {
        switch (unit)
        {
            case TemperatureUnit.Kelvin:
                _Kelvin = temperature;
                break;
            case TemperatureUnit.Celsius:
                Celsius = temperature;
                break;
            case TemperatureUnit.Fahrenheit:
                Fahrenheit = temperature;
                break;
            default:
                throw new ArgumentException(
                  "The temperature unit '" + unit.ToString() + "' is unknown.");
        }
    }

    /// <summary>
    /// Gets or sets the temperature value in Kelvin.
    /// </summary>
    public double Kelvin
    {
        get { return _Kelvin; }
        set { _Kelvin = value; }
    }

    /// <summary>
    /// Gets or sets the temperature value in Celsius.
    /// </summary>
    public double Celsius
    {
        get { return KelvinToCelsius(_Kelvin); }
        set { _Kelvin = CelsiusToKelvin(value); }
    }

    /// <summary>
    /// Gets or sets the temperature value in Fahrenheit.
    /// </summary>
    public double Fahrenheit
    {
        get { return KelvinToFahrenheit(_Kelvin); }
        set { _Kelvin = FahrenheitToKelvin(value); }
    }

    /// <summary>
    /// Gets the temperature value in the specified unit of measurement.
    /// </summary>
    /// <param name="unit">The unit of measurement
    /// in which the temperature should be retrieved.</param>
    /// <returns>The temperature value in the specified 
    /// <paramref name="unit"/>.</returns>
    public double ValueIn(TemperatureUnit unit)
    {
        switch (unit)
        {
            case TemperatureUnit.Kelvin: return _Kelvin;
            case TemperatureUnit.Celsius: return Celsius;
            case TemperatureUnit.Fahrenheit: return Fahrenheit;
            default: throw new ArgumentException(
               "Unknown temperature unit '" + unit.ToString() + "'.");
        }
    }

    /// <summary>
    /// Returns a string representation of the temperature value.
    /// </summary>
    /// <param name="format">
    /// A single format specifier that indicates how to format the value of this
    /// temperature. The format parameter can be "G", 
    /// "C", "F", or "K". If format
    /// is null or the empty string (""), "G" is used.
    /// </param>
    /// <param name="provider">
    /// An IFormatProvider reference that supplies culture-specific formatting
    /// services.
    /// </param>
    /// <returns>A string representation of the temperature.</returns>
    /// <exception cref="FormatException">
    /// The value of format is not null, the empty string (""), "G", "C", "F", or
    /// "K".
    /// </exception>
    public string ToString(string format, IFormatProvider provider)
    {
        if (String.IsNullOrEmpty(format)) format = "G";
        if (provider == null) provider = CultureInfo.CurrentCulture;

        switch (format.ToUpperInvariant())
        {
            case "G":
            case "C":
                return Celsius.ToString("F2", provider) + " °C";
            case "F":
                return Fahrenheit.ToString("F2", provider) + " °F";
            case "K":
                return _Kelvin.ToString("F2", provider) + " K";
            default:
                throw new FormatException(
                      String.Format("The {0} format string is not supported.", format));
        }
    }

    /// <summary>
    /// Returns a string representation of the temperature value.
    /// </summary>
    /// <param name="format">
    /// A single format specifier that indicates how to format the value of this
    /// temperature. The format parameter can be "G", 
    /// "C", "F", or "K". If format
    /// is null or the empty string (""), "G" is used.
    /// </param>
    /// <returns>A string representation of the temperature.</returns>
    /// <exception cref="FormatException">
    /// The value of format is not null, 
    /// the empty string (""), "G", "C", "F", or
    /// "K".
    /// </exception>
    public string ToString(string format)
    {
        return ToString(format, null);
    }

    /// <summary>
    /// Returns a string representation of the temperature value.
    /// </summary>
    /// <returns>A string representation of the temperature.</returns>
    public override string ToString()
    {
        return ToString(null, null);
    }

    /// <summary>
    /// Returns a string representation of the temperature value.
    /// </summary>
    /// <param name="unit">
    /// The temperature unit as which the temperature value should be displayed.
    /// </param>
    /// <param name="provider">
    /// An IFormatProvider reference that supplies culture-specific formatting
    /// services.
    /// </param>
    /// <returns>A string representation of the temperature.</returns>
    public string ToString(TemperatureUnit unit, IFormatProvider provider)
    {
        switch (unit)
        {
            case TemperatureUnit.Celsius:
                return ToString("C", provider);
            case TemperatureUnit.Fahrenheit:
                return ToString("F", provider);
            case TemperatureUnit.Kelvin:
                return ToString("K", provider);
            default:
                throw new FormatException("The temperature unit '" + 
                      unit.ToString() + "' is unknown.");
        }
    }

    /// <summary>
    /// Returns a string representation of the temperature value.
    /// </summary>
    /// <param name="unit">
    /// The temperature unit as which the temperature value should be displayed.
    /// </param>
    /// <returns>A string representation of the temperature.</returns>
    public string ToString(TemperatureUnit unit)
    {
        return ToString(unit, null);
    }

    /// <summary>
    /// Compares this instance to a specified Temperature object and returns an indication
    /// of their relative values.
    /// </summary>
    /// <param name="value">A Temperature object
    ///    to compare to this instance.</param>
    /// <returns>
    /// A signed number indicating the relative values of this instance and value.
    /// Value Description A negative integer This instance is less than value. Zero
    /// This instance is equal to value. A positive integer This instance is greater
    /// than value.
    /// </returns>
    public int CompareTo(Temperature value)
    {
        return _Kelvin.CompareTo(value._Kelvin);
    }

    /// <summary>
    /// Compares this instance to a specified object and returns an indication of
    /// their relative values.
    /// </summary>
    /// <param name="value">An object to compare, or null.</param>
    /// <returns>
    /// A signed number indicating the relative values of this instance and value.
    /// Value Description A negative integer This instance is less than value. Zero
    /// This instance is equal to value. A positive integer This instance is greater
    /// than value, or value is null.
    /// </returns>
    /// <exception cref="ArgumentException">
    /// The value is not a Temperature.
    /// </exception>
    public int CompareTo(object value)
    {
        if (value == null) return 1;
        if (!(value is Temperature)) throw new ArgumentException();
            return CompareTo((Temperature)value);
    }

    /// <summary>
    /// Determines whether or not the given temperature is considered equal to this instance.
    /// </summary>
    /// <param name="value">The temperature to compare to this instance.</param>
    /// <returns>True if the temperature is considered equal
    ///    to this instance. Otherwise, false.</returns>
    public bool Equals(Temperature value)
    {
        return _Kelvin == value._Kelvin;
    }

    /// <summary>
    /// Determines whether or not the given object is considered equal to the temperature.
    /// </summary>
    /// <param name="value">The object to compare to the temperature.</param>
    /// <returns>True if the object is considered equal
    ///     to the temperature. Otherwise, false.</returns>
    public override bool Equals(object value)
    {
        if (value == null) return false;
        if (!(value is Temperature)) return false;

        return Equals((Temperature)value);
    }

    /// <summary>
    /// Returns the hash code for this instance.
    /// </summary>
    /// <returns>A 32-bit signed integer hash code.</returns>
    public override int GetHashCode()
    {
        return _Kelvin.GetHashCode();
    }

    /// <summary>
    /// Determines the equality of two temperatures.
    /// </summary>
    /// <param name="t1">The first temperature to be compared.</param>
    /// <param name="t2">The second temperature to be compared.</param>
    /// <returns>True if the temperatures are equal. Otherwise, false.</returns>
    public static bool operator ==(Temperature t1, Temperature t2)
    {
        return t1.Equals(t2);
    }

    /// <summary>
    /// Determines the inequality of two temperatures.
    /// </summary>
    /// <param name="t1">The first temperature to be compared.</param>
    /// <param name="t2">The second temperature to be compared.</param>
    /// <returns>True if the temperatures are NOT equal. Otherwise, false.</returns>
    public static bool operator !=(Temperature t1, Temperature t2)
    {
        return !t1.Equals(t2);
    }

    /// <summary>
    /// Determines whether one temperature is considered greater than another.
    /// </summary>
    /// <param name="t1">The first temperature to be compared.</param>
    /// <param name="t2">The second temperature to be compared.</param>
    /// <returns>True if the first temperature is greater than the second. 
    /// Otherwise, false.</returns>
    public static bool operator >(Temperature t1, Temperature t2)
    {
        return t1._Kelvin > t2._Kelvin;
    }

    /// <summary>
    /// Determines whether one temperature is considered less than another.
    /// </summary>
    /// <param name="t1">The first temperature to be compared.</param>
    /// <param name="t2">The second temperature to be compared.</param>
    /// <returns>True if the first temperature is less than the second. 
    /// Otherwise, false.</returns>
    public static bool operator <(Temperature t1, Temperature t2)
    {
        return t1._Kelvin < t2._Kelvin;
    }

    /// <summary>
    /// Determines whether one temperature is considered greater to or equal to another.
    /// </summary>
    /// <param name="t1">The first temperature to be compared.</param>
    /// <param name="t2">The second temperature to be compared.</param>
    /// <returns>
    /// True if the first temperature is greater to or equal to the second. Otherwise, false.
    /// </returns>
    public static bool operator >=(Temperature t1, Temperature t2)
    {
        return t1._Kelvin >= t2._Kelvin;
    }

    /// <summary>
    /// Determines whether one temperature is considered less than or equal to another.
    /// </summary>
    /// <param name="t1">The first temperature to be compared.</param>
    /// <param name="t2">The second temperature to be compared.</param>
    /// <returns>
    /// True if the first temperature is less than or equal to the second. Otherwise, false.
    /// </returns>
    public static bool operator <=(Temperature t1, Temperature t2)
    {
        return t1._Kelvin <= t2._Kelvin;
    }

    /// <summary>
    /// Adds two instances of the temperature object.
    /// </summary>
    /// <param name="t1">The temperature on the left-hand side of the operator.
    /// </param>
    /// <param name="t2">The temperature on the right-hand side of the operator.
    /// </param>
    /// <returns>The sum of the two temperatures.</returns>
    public static Temperature operator +(Temperature t1, Temperature t2)
    {
        return new Temperature(t1._Kelvin + t2._Kelvin);
    }

    /// <summary>
    /// Subtracts one instance from another.
    /// </summary>
    /// <param name="t1">The temperature on the left-hand side of the operator.
    /// </param>
    /// <param name="t2">The temperature on the right-hand side of the operator.
    /// </param>
    /// <returns>The difference of the two temperatures.</returns>
    public static Temperature operator -(Temperature t1, Temperature t2)
    {
        return new Temperature(t1._Kelvin - t2._Kelvin);
    }

    /// <summary>
    /// Multiplies two instances of the temperature object.
    /// </summary>
    /// <param name="t1">The temperature on the left-hand side of the operator.
    /// </param>
    /// <param name="t2">The temperature on the right-hand side of the operator.
    /// </param>
    /// <returns>The product of the two temperatures.</returns>
    public static Temperature operator *(Temperature t1, Temperature t2)
    {
        return new Temperature(t1._Kelvin * t2._Kelvin);
    }

    /// <summary>
    /// Divides one instance of a temperature object by another.
    /// </summary>
    /// <param name="t1">The temperature on the left-hand side of the operator.
    /// </param>
    /// <param name="t2">The temperature on the right-hand side of the operator.
    /// </param>
    /// <returns>The quotient of the two temperature.</returns>
    public static Temperature operator /(Temperature t1, Temperature t2)
    {
        // TODO: Throw a divide-by-zero exception if needed.
        return new Temperature(t1._Kelvin / t2._Kelvin);
    }

    /// <summary>
    /// Finds the remainder when one instance of a temperature object is divided by another.
    /// </summary>
    /// <param name="t1">The temperature on the left-hand side of the operator.
    /// </param>
    /// <param name="t2">The temperature on the right-hand side of the operator.
    /// </param>
    /// <returns>The remainder after the quotient is found.</returns>
    public static Temperature operator %(Temperature t1, Temperature t2)
    {
        // TODO: Throw a divide-by-zero exception if needed.
        return new Temperature(t1._Kelvin % t2._Kelvin);
    }

    /// <summary>
    /// Converts a Kelvin temperature value to Celsius.
    /// </summary>
    /// <param name="kelvin">The Kelvin value to convert to Celsius.
    /// </param>
    /// <returns>The Kelvin value in Celsius.</returns>
    public static double KelvinToCelsius(double kelvin)
    {
        return kelvin - 273.15;
    }

    /// <summary>
    /// Converts a Celsius value to Kelvin.
    /// </summary>
    /// <param name="celsius">The Celsius value to convert to Kelvin.
    /// </param>
    /// <returns>The Celsius value in Kelvin.</returns>
    public static double CelsiusToKelvin(double celsius)
    {
        return celsius + 273.15;
    }

    /// <summary>
    /// Converts a Kelvin value to Fahrenheit.
    /// </summary>
    /// <param name="kelvin">The Kelvin value to convert to Fahrenheit.
    /// </param>
    /// <returns>The Kelvin value in Fahrenheit.</returns>
    public static double KelvinToFahrenheit(double kelvin)
    {
        return kelvin * 9 / 5 - 459.67;
    }

    /// <summary>
    /// Converts a Fahrenheit value to Kelvin.
    /// </summary>
    /// <param name="fahrenheit">The Fahrenheit value to convert to Kelvin.
    /// </param>
    /// <returns>The Fahrenheit value in Kelvin.</returns>
    public static double FahrenheitToKelvin(double fahrenheit)
    {
        return (fahrenheit + 459.67) * 5 / 9;
    }

    /// <summary>
    /// Converts a Fahrenheit value to Celsius.
    /// </summary>
    /// <param name="fahrenheit">The Fahrenheit value to convert to Celsius.
    /// </param>
    /// <returns>The Fahrenheit value in Celsius.</returns>
    public static double FahrenheitToCelsius(double fahrenheit)
    {
        return (fahrenheit - 32) * 5 / 9;
    }

    /// <summary>
    /// Converts a Celsius value to Fahrenheit.
    /// </summary>
    /// <param name="celsius">The Celsius value to convert to Fahrenheit.
    /// </param>
    /// <returns>The Celsius value in Fahrenheit.</returns>
    public static double CelsiusToFahrenheit(double celsius)
    {
        return celsius * 9 / 5 + 32;
    }
}