Skip to content

Instantly share code, notes, and snippets.

@MovGP0
Last active August 29, 2015 14:24
Show Gist options
  • Save MovGP0/40a9cca249ab2e385e53 to your computer and use it in GitHub Desktop.
Save MovGP0/40a9cca249ab2e385e53 to your computer and use it in GitHub Desktop.
Money and Percent types
using System;
using System.Runtime.Serialization;
using System.Xml.Serialization;
namespace CN.Lib.Types
{
[Serializable]
[DataContract]
public struct Money : IEquatable<Money>, IComparable<Money>, IFormattable, ISerializable, IConvertible
{
[DataMember(Name = "amount", IsRequired = true)]
[XmlText]
private readonly decimal _amount;
public Money(decimal amount)
{
_amount = amount;
}
public static Money Zero
{
get { return new Money(0m); }
}
public static Money Cent
{
get { return new Money(SiPrefix.Centi); }
}
public static Money Million
{
get { return new Money(SiPrefix.Mega); }
}
public static Money Thousand
{
get { return new Money(SiPrefix.Kilo); }
}
public static Money Hundred
{
get { return new Money(SiPrefix.Hecto); }
}
public static Money One
{
get { return new Money(decimal.One); }
}
public static Money MinusOne
{
get { return new Money(decimal.MinusOne); }
}
public static Money MinValue
{
get { return new Money(decimal.MinValue); }
}
public static Money MaxValue
{
get { return new Money(decimal.MaxValue); }
}
public int CompareTo(Money other)
{
return _amount.CompareTo(other._amount);
}
public bool Equals(Money other)
{
return _amount == other._amount;
}
public string ToString(string format, IFormatProvider formatProvider)
{
return _amount.ToString(format, formatProvider);
}
public static implicit operator Money(decimal amount)
{
return new Money(amount);
}
public static explicit operator decimal(Money money)
{
return money._amount;
}
public decimal ToDecimal()
{
return _amount;
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
{
return false;
}
return obj is Money && Equals((Money) obj);
}
public override int GetHashCode()
{
return _amount.GetHashCode();
}
public static bool operator ==(Money left, Money right)
{
return left.Equals(right);
}
public static bool operator <(Money left, Money right)
{
return left._amount < right._amount;
}
public static bool operator >(Money left, Money right)
{
return left._amount > right._amount;
}
public static bool operator <=(Money left, Money right)
{
return left._amount <= right._amount;
}
public static bool operator >=(Money left, Money right)
{
return left._amount >= right._amount;
}
public static bool operator !=(Money left, Money right)
{
return !left.Equals(right);
}
public static Money operator -(Money amount)
{
return -(amount._amount);
}
public static Percent operator /(Money numerator, Money denumerator)
{
return new Percent(numerator._amount/denumerator._amount);
}
public static Money operator +(Money left, Money right)
{
return new Money(left._amount + right._amount);
}
public static Money operator -(Money left, Money right)
{
return new Money(left._amount - right._amount);
}
public static Money operator *(Money value, decimal scalarValue)
{
return new Money(value._amount*scalarValue);
}
public static Money operator *(Money value, Percent percent)
{
return new Money(value._amount*(decimal) percent);
}
public static Money operator *(Percent percent, Money value)
{
return new Money(value._amount*(decimal) percent);
}
public static Money operator *(decimal scalarValue, Money value)
{
return new Money(value._amount*scalarValue);
}
public static Money operator /(Money value, decimal scalarValue)
{
return new Money(value._amount/scalarValue);
}
public override string ToString()
{
return string.Format("{0:0.00}", Math.Round(_amount, 2, MidpointRounding.AwayFromZero));
}
public string ToString(string format)
{
return _amount.ToString(format);
}
public string ToString(IFormatProvider formatProvider)
{
return _amount.ToString(formatProvider);
}
#region ISerializable
/// <summary>
/// Deserialization constructor
/// </summary>
/// <param name="info"></param>
/// <param name="context"></param>
public Money(SerializationInfo info, StreamingContext context)
{
_amount = info.GetDecimal("amount");
}
/// <summary>
/// Serialization method
/// </summary>
/// <param name="info"></param>
/// <param name="context"></param>
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("amount", _amount);
}
#endregion
#region IConvertible
public TypeCode GetTypeCode()
{
return TypeCode.Decimal;
}
public bool ToBoolean(IFormatProvider provider)
{
return Convert.ToBoolean(_amount, provider);
}
public byte ToByte(IFormatProvider provider)
{
return Convert.ToByte(_amount, provider);
}
public char ToChar(IFormatProvider provider)
{
return Convert.ToChar(_amount, provider);
}
public DateTime ToDateTime(IFormatProvider provider)
{
return Convert.ToDateTime(_amount, provider);
}
public decimal ToDecimal(IFormatProvider provider)
{
return Convert.ToDecimal(_amount, provider);
}
public double ToDouble(IFormatProvider provider)
{
return Convert.ToDouble(_amount, provider);
}
public short ToInt16(IFormatProvider provider)
{
return Convert.ToInt16(_amount, provider);
}
public int ToInt32(IFormatProvider provider)
{
return Convert.ToInt32(_amount, provider);
}
public long ToInt64(IFormatProvider provider)
{
return Convert.ToInt64(_amount, provider);
}
public sbyte ToSByte(IFormatProvider provider)
{
return Convert.ToSByte(_amount, provider);
}
public float ToSingle(IFormatProvider provider)
{
return Convert.ToSingle(_amount, provider);
}
public object ToType(Type conversionType, IFormatProvider provider)
{
return Convert.ChangeType(_amount, conversionType, provider);
}
public ushort ToUInt16(IFormatProvider provider)
{
return Convert.ToUInt16(_amount, provider);
}
public uint ToUInt32(IFormatProvider provider)
{
return Convert.ToUInt32(_amount, provider);
}
public ulong ToUInt64(IFormatProvider provider)
{
return Convert.ToUInt64(_amount, provider);
}
#endregion
}
}
using System;
using System.Collections.Generic;
using System.Linq;
namespace CN.Lib.Types
{
public static class MoneyExtensions
{
public static Money Sum(this IEnumerable<Money> amounts)
{
var sum = new Money(0m);
return amounts.Aggregate(sum, (current, ammount) => current + ammount);
}
public static Money Sum<T>(this IEnumerable<T> amounts, Func<T, Money> func)
{
return amounts.Select(func).Sum();
}
public static Money Sum(this IEnumerable<Money> amounts, Func<Money, bool> func)
{
return amounts.Where(func).Sum();
}
public static Money Average(this IEnumerable<Money> amounts)
{
return amounts.Select(v => (decimal)v).Average();
}
/// <summary>
/// Absolute value.
/// </summary>
/// <param name="percentage"></param>
/// <returns></returns>
public static Money Abs(this Money percentage)
{
return Math.Abs((decimal)percentage);
}
/// <summary>
/// Rounding to cent precision.
/// </summary>
/// <param name="amount"></param>
/// <returns></returns>
public static Money Round(this Money amount)
{
return Math.Round((decimal) amount, 2);
}
public static Money Round(this Money amount, int decimals)
{
return Math.Round((decimal) amount, decimals);
}
/// <summary>
/// Rounding to cent precision.
/// </summary>
/// <param name="amount"></param>
/// <returns></returns>
public static Money Round(this Money amount, MidpointRounding rounding)
{
return Math.Round((decimal) amount, 2, rounding);
}
public static Money Round(this Money amount, int decimals, MidpointRounding rounding)
{
return Math.Round((decimal) amount, decimals, rounding);
}
public static int Sign(this Money amount)
{
return Math.Sign((decimal)amount);
}
/// <summary>
/// Compares if a given value is within 6 significant digits to <value>0m</value>.
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public static bool IsApproximatelyZero(this Money value)
{
return IsApproximately(value, Money.Zero);
}
/// <summary>
/// Compares two decimal numbers with a precision of 6 significant digits.
/// </summary>
/// <param name="value"></param>
/// <param name="other"></param>
/// <returns></returns>
public static bool IsApproximately(this Money value, Money other)
{
Money ε = 0.000001m;
return value.IsApproximately(other, ε);
}
/// <summary>
/// Compares if two decimal numbers are within a given difference.
/// </summary>
/// <param name="value"></param>
/// <param name="other"></param>
/// <param name="epsilon">The maximal difference between the two numbers.</param>
/// <returns></returns>
public static bool IsApproximately(this Money value, Money other, Money epsilon)
{
return value < (other + epsilon)
&& value > (other - epsilon);
}
}
}
using System;
using System.Runtime.Serialization;
using System.Xml.Serialization;
namespace CN.Lib.Types
{
[Serializable]
[DataContract(Name = "Percent")]
public struct Percent : IEquatable<Percent>, IComparable<Percent>, IFormattable, IConvertible
{
[DataMember(Name="percentage", IsRequired = true)]
[XmlText]
private readonly decimal _value;
public static Percent Zero
{
get { return new Percent(0m); }
}
public static Percent Hundred
{
get { return new Percent(1m); }
}
public static Percent MaxValue
{
get { return new Percent(decimal.MaxValue); }
}
public static Percent MinValue
{
get { return new Percent(decimal.MinValue); }
}
public Percent(decimal value)
{
_value = value;
}
public bool Equals(Percent other)
{
return _value.Equals(other._value);
}
public decimal ToDecimal()
{
return _value;
}
public static explicit operator decimal(Percent percent)
{
return percent._value;
}
public static implicit operator Percent(decimal value)
{
return new Percent(value);
}
public int CompareTo(Percent other)
{
return _value.CompareTo(other._value);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
{
return false;
}
return obj is Percent && Equals((Percent) obj);
}
public override int GetHashCode()
{
return _value.GetHashCode();
}
public static bool operator ==(Percent left, Percent right)
{
return left.Equals(right);
}
public static bool operator <(Percent left, Percent right)
{
return left._value < right._value;
}
public static bool operator >(Percent left, Percent right)
{
return left._value > right._value;
}
public static bool operator <=(Percent left, Percent right)
{
return left._value <= right._value;
}
public static bool operator >=(Percent left, Percent right)
{
return left._value >= right._value;
}
public static bool operator !=(Percent left, Percent right)
{
return !left.Equals(right);
}
public static Percent operator -(Percent percentage)
{
return -(percentage._value);
}
public static Percent operator +(Percent left, Percent right)
{
return new Percent(left._value + right._value);
}
public static Percent operator -(Percent left, Percent right)
{
return new Percent(left._value - right._value);
}
public static Percent operator *(Percent left, Percent right)
{
return new Percent(left._value * right._value);
}
public static Percent operator *(decimal left, Percent right)
{
return new Percent(left * right._value);
}
public static Percent operator *(Percent left, decimal right)
{
return new Percent(left._value * right);
}
public override string ToString()
{
return string.Format("{0:P2}", Math.Round(_value, 2, MidpointRounding.AwayFromZero));
}
public string ToString(string format)
{
return _value.ToString(format);
}
public string ToString(IFormatProvider formatProvider)
{
return _value.ToString(formatProvider);
}
public string ToString(string format, IFormatProvider formatProvider)
{
return _value.ToString(format, formatProvider);
}
#region ISerializable
/// <summary>
/// Deserialization constructor
/// </summary>
/// <param name="info"></param>
/// <param name="context"></param>
public Percent(SerializationInfo info, StreamingContext context)
{
_value = info.GetDecimal("percentage");
}
/// <summary>
/// Serialization method
/// </summary>
/// <param name="info"></param>
/// <param name="context"></param>
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("percentage", _value);
}
#endregion
#region IConvertible
public TypeCode GetTypeCode()
{
return TypeCode.Decimal;
}
public bool ToBoolean(IFormatProvider provider)
{
return Convert.ToBoolean(_value, provider);
}
public byte ToByte(IFormatProvider provider)
{
return Convert.ToByte(_value, provider);
}
public char ToChar(IFormatProvider provider)
{
return Convert.ToChar(_value, provider);
}
public DateTime ToDateTime(IFormatProvider provider)
{
return Convert.ToDateTime(_value, provider);
}
public decimal ToDecimal(IFormatProvider provider)
{
return Convert.ToDecimal(_value, provider);
}
public double ToDouble(IFormatProvider provider)
{
return Convert.ToDouble(_value, provider);
}
public short ToInt16(IFormatProvider provider)
{
return Convert.ToInt16(_value, provider);
}
public int ToInt32(IFormatProvider provider)
{
return Convert.ToInt32(_value, provider);
}
public long ToInt64(IFormatProvider provider)
{
return Convert.ToInt64(_value, provider);
}
public sbyte ToSByte(IFormatProvider provider)
{
return Convert.ToSByte(_value, provider);
}
public float ToSingle(IFormatProvider provider)
{
return Convert.ToSingle(_value, provider);
}
public object ToType(Type conversionType, IFormatProvider provider)
{
return Convert.ChangeType(_value, conversionType, provider);
}
public ushort ToUInt16(IFormatProvider provider)
{
return Convert.ToUInt16(_value, provider);
}
public uint ToUInt32(IFormatProvider provider)
{
return Convert.ToUInt32(_value, provider);
}
public ulong ToUInt64(IFormatProvider provider)
{
return Convert.ToUInt64(_value, provider);
}
#endregion
}
}
using System;
using System.Collections.Generic;
using System.Linq;
namespace CN.Lib.Types
{
public static class PercentExtensions
{
public static Percent Sum(this IEnumerable<Percent> percentages)
{
var sum = new Percent(0m);
return percentages.Aggregate(sum, (current, percentage) => current + percentage);
}
public static Percent Sum<T>(this IEnumerable<T> amounts, Func<T, Percent> func)
{
return amounts.Select(func).Sum();
}
public static Percent Sum(this IEnumerable<Percent> amounts, Func<Percent, bool> func)
{
return amounts.Where(func).Sum();
}
public static Percent Average(this IEnumerable<Percent> percentages)
{
return percentages.Select(v => (decimal) v).Average();
}
public static Percent Abs(this Percent percentage)
{
return Math.Abs((decimal) percentage);
}
public static Percent Round(this Percent percentage)
{
return Math.Round((decimal)percentage, 4);
}
public static Percent Round(this Percent percentage, int decimals)
{
return Math.Round((decimal)percentage, decimals);
}
public static Percent Round(this Percent percentage, MidpointRounding rounding)
{
return Math.Round((decimal)percentage, rounding);
}
public static Percent Round(this Percent percentage, int decimals, MidpointRounding rounding)
{
return Math.Round((decimal)percentage, decimals, rounding);
}
}
}
namespace CN.Lib.Types
{
public static class SiPrefix
{
public static decimal Yocto
{
get { return 0.000000000000000000000001m; }
}
public static decimal Zepto
{
get { return 0.000000000000000000001m; }
}
public static decimal Atto
{
get { return 0.000000000000000001m; }
}
public static decimal Femto
{
get { return 0.000000000000001m; }
}
public static decimal Pico
{
get { return 0.000000000001m; }
}
public static decimal Nano
{
get { return 0.000000001m; }
}
/// <summary>
/// Millionth
/// </summary>
public static decimal Micro
{
get { return 0.000001m; }
}
/// <summary>
/// Thousandth
/// </summary>
public static decimal Milli
{
get { return 0.001m; }
}
/// <summary>
/// Hundredth
/// </summary>
public static decimal Centi
{
get { return 0.01m; }
}
/// <summary>
/// Tenth
/// </summary>
public static decimal Deci
{
get { return 0.1m; }
}
/// <summary>
/// One
/// </summary>
public static decimal One
{
get { return decimal.One; }
}
public static decimal Yotta
{
get { return 1000000000000000000000000m; }
}
public static decimal Zetta
{
get { return 1000000000000000000000m; }
}
public static decimal Exa
{
get { return 1000000000000000000m; }
}
public static decimal Peta
{
get { return 1000000000000000m; }
}
public static decimal Tera
{
get { return 1000000000000m; }
}
public static decimal Giga
{
get { return 1000000000m; }
}
/// <summary>
/// Million
/// </summary>
public static decimal Mega
{
get { return 1000000m; }
}
/// <summary>
/// Thousand
/// </summary>
public static decimal Kilo
{
get { return 1000m; }
}
/// <summary>
/// Hundred
/// </summary>
public static decimal Hecto
{
get { return 100m; }
}
/// <summary>
/// Ten
/// </summary>
public static decimal Deca
{
get { return 10m; }
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment