A C# Temperature Struct

Update
On the advice of someone over at Code Project, I removed the arithmetic operator overloads in favor of a Change method. This method returns the temperature change between two values according to the measurement unit of your choosing.
End Update

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, and etc., 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 returned.</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)
    {
        // TODO: Should the null check come after the type check?
 
        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 temperature is considered equal to this instance
    /// within the given <paramref name="tolerance"/>. The <paramref name="unit"/> of temperature
    /// is used to evaluate the <paramref name="tolerance"/>.
    /// </summary>
    /// <param name="value">The temperature to compare to this instance.</param>
    /// <param name="tolerance">The deviation allowed for the temperatures to be considered equal.</param>
    /// <param name="unit">The unit of measurement that defines the <paramref name="tolerance"/>.</param>
    /// <returns>True if the temperatures are considered equal within the given tolerance. Otherwise, false.</returns>
    public bool Equals(Temperature value, double tolerance, TemperatureUnit unit)
    {
        return Math.Abs(ValueIn(unit) - value.ValueIn(unit)) <= tolerance;
    }
 
    /// <summary>
    /// Determines whether or not the given temperature is considered equal to this instance
    /// within the given <paramref name="tolerance"/>. Kelvin is used to evaluate the <paramref name="tolerance"/>.
    /// </summary>
    /// <param name="value">The temperature to compare to this instance.</param>
    /// <param name="tolerance">The deviation allowed for the temperatures to be considered equal.</param>
    /// <returns>True if the temperatures are considered equal within the given tolerance. Otherwise, false.</returns>
    public bool Equals(Temperature value, double tolerance)
    {
        return Equals(value, tolerance, TemperatureUnit.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>
    /// Finds the temperature change between the two temperatures using the specified <paramref name="unit"/>.
    /// </summary>
    /// <param name="value">The temperature to be subtracted from this temperature.</param>
    /// <param name="unit">The unit of measurement to use during the subtraction.</param>
    /// <returns>The change between the two temperatures, signed to indicate an increase or decrease in temperature.</returns>
    public double Change(Temperature value, TemperatureUnit unit)
    {
        return (ValueIn(unit) - value.ValueIn(unit)) * -1;
    }
 
    /// <summary>
    /// Finds the temperature change between the two temperatures using the Kelvin unit of measurement.
    /// </summary>
    /// <param name="value">The temperature to be subtracted from this temperature.</param>
    /// <returns>The change between the two temperatures, signed to indicate an increase or decrease in temperature.</returns>
    public double Change(Temperature value)
    {
        return Change(value, TemperatureUnit.Kelvin);
    }
 
    /// <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>
    /// 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;
    }
}
Tags:

No comments for 'A C# Temperature Struct'

Post new comment

The content of this field is kept private and will not be shown publicly.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd>
  • Lines and paragraphs break automatically.
  • Image links with 'rel="lightbox"' in the <a> tag will appear in a Lightbox when clicked on.

More information about formatting options

CAPTCHA
Please verify your species.