In my application I want all my properties storing money amounts to be rounded to n
decimal places.
For code clarity, I'd rather have a custom type MoneyAmount
which all my corresponding fields would have, instead of having to put a `Math.Round(value, n)' in all the property getters/setters.
Is there a neat way to achieve this?
I saw this post about overloading assignment operators - is this the suggested approach?
EDIT: Given the multiple views, I post the full code I derived here:
public struct MoneyAmount {
const int N = 4;
private readonly double _value;
public MoneyAmount(double value) {
_value = Math.Round(value, N);
}
#region mathematical operators
public static MoneyAmount operator +(MoneyAmount d1, MoneyAmount d2) {
return new MoneyAmount(d1._value + d2._value);
}
public static MoneyAmount operator -(MoneyAmount d1, MoneyAmount d2) {
return new MoneyAmount(d1._value - d2._value);
}
public static MoneyAmount operator *(MoneyAmount d1, MoneyAmount d2) {
return new MoneyAmount(d1._value * d2._value);
}
public static MoneyAmount operator /(MoneyAmount d1, MoneyAmount d2) {
return new MoneyAmount(d1._value / d2._value);
}
#endregion
#region logical operators
public static bool operator ==(MoneyAmount d1, MoneyAmount d2) {
return d1._value == d2._value;
}
public static bool operator !=(MoneyAmount d1, MoneyAmount d2) {
return d1._value != d2._value;
}
public static bool operator >(MoneyAmount d1, MoneyAmount d2) {
return d1._value > d2._value;
}
public static bool operator >=(MoneyAmount d1, MoneyAmount d2) {
return d1._value >= d2._value;
}
public static bool operator <(MoneyAmount d1, MoneyAmount d2) {
return d1._value < d2._value;
}
public static bool operator <=(MoneyAmount d1, MoneyAmount d2) {
return d1._value <= d2._value;
}
#endregion
#region Implicit conversions
/// <summary>
/// Implicit conversion from int to MoneyAmount.
/// Implicit: No cast operator is required.
/// </summary>
public static implicit operator MoneyAmount(int value) {
return new MoneyAmount(value);
}
/// <summary>
/// Implicit conversion from float to MoneyAmount.
/// Implicit: No cast operator is required.
/// </summary>
public static implicit operator MoneyAmount(float value) {
return new MoneyAmount(value);
}
/// <summary>
/// Implicit conversion from double to MoneyAmount.
/// Implicit: No cast operator is required.
/// </summary>
public static implicit operator MoneyAmount(double value) {
return new MoneyAmount(value);
}
/// <summary>
/// Implicit conversion from decimal to MoneyAmount.
/// Implicit: No cast operator is required.
/// </summary>
public static implicit operator MoneyAmount(decimal value) {
return new MoneyAmount(Convert.ToDouble(value));
}
#endregion
#region Explicit conversions
/// <summary>
/// Explicit conversion from MoneyAmount to int.
/// Explicit: A cast operator is required.
/// </summary>
public static explicit operator int(MoneyAmount value) {
return (int)value._value;
}
/// <summary>
/// Explicit conversion from MoneyAmount to float.
/// Explicit: A cast operator is required.
/// </summary>
public static explicit operator float(MoneyAmount value) {
return (float)value._value;
}
/// <summary>
/// Explicit conversion from MoneyAmount to double.
/// Explicit: A cast operator is required.
/// </summary>
public static explicit operator double(MoneyAmount value) {
return (double)value._value;
}
/// <summary>
/// Explicit conversion from MoneyAmount to decimal.
/// Explicit: A cast operator is required.
/// </summary>
public static explicit operator decimal(MoneyAmount value) {
return Convert.ToDecimal(value._value);
}
#endregion
}
I'd suggest the following:
double
. double
parameter, this constructor rounds the value and assigns it to the internal field. double
, like +, -, etc. But also casts/conversions from/to other types. Every operation produces a new instance of MoneyAmount with a rounded value. IFormattable
, IComparable
and IConvertible
. Short example:
public struct MoneyAmount
{
const int N = 4;
private readonly double _value;
public MoneyAmount(double value)
{
_value = Math.Round(value, N);
}
// Example of one member of double:
public static MoneyAmount operator *(MoneyAmount d1, MoneyAmount d2)
{
return new MoneyAmount(d1._value * d2._value);
}
/// <summary>
/// Implicit conversion from double to MoneyAmount.
/// Implicit: No cast operator is required.
/// </summary>
public static implicit operator MoneyAmount(double value)
{
return new MoneyAmount(value);
}
/// <summary>
/// Explicit conversion from MoneyAmount to double.
/// Explicit: A cast operator is required.
/// </summary>
public static explicit operator double(MoneyAmount value)
{
return value._value;
}
/// <summary>
/// Explicit conversion from MoneyAmount to int.
/// Explicit: A cast operator is required.
/// </summary>
public static explicit operator MoneyAmount(int value)
{
return new MoneyAmount(value);
}
/// <summary>
/// Explicit conversion from MoneyAmount to int.
/// Explicit: A cast operator is required.
/// </summary>
public static explicit operator int(MoneyAmount value)
{
return (int)value._value;
}
// All other members here...
}
I realize: The double
has a lot of members...
With these operators, the following code is possible:
MoneyAmount m = 1.50; // Assignment from a double.
MoneyAmount n = 10; // Assignment from an integer.
m += n; // Mathematical operation with another MoneyAmount .
m *= 10; // Mathematical operation with an integer.
m -= 12.50; // Mathematical operation with a double.
EDIT
All conversion methods you may want to implement:
Explicit MoneyAmount --> decimal
Implicit int--> MoneyAmount
All mathematical operations you may want to implement:
All relational operations you may want to implement:
With all these operations your have all basics covered.
This gets big very quickly. Writing a struct is easy, as demonstrated in @MartinMulder's answer, but consider that you will want to overload a number of combinations of operators, as well as including a few implicit/explicit casts as well.
Consider that you may want to do mathematical operations on MoneyAmount
MoneyAmount
+ MoneyAmount
MoneyAmount
+ double
MoneyAmount
+ int
MoneyAmount
+ decimal
That is 4 overloads of the +
operator. Rinse and repeat for -
, /
, *
(and possibly %
). You'll also want to overload <
, <=
, ==
and >
, >=
. Thats something like 30 operator overloads. Phew! Thats a lot of static methods.
public static MoneyAmount operator +(MoneyAmount d1, double d2)
{
return new MoneyAmount((decimal)(d1._value + d2));
}
Now consider that instead of this code
MoneyAmount m = new MoneyAmount(1.234);
You wanted to do this:
MoneyAmount m = 1.234;
That can be achieved with an implicit cast operator.
public static implicit operator MoneyAmount(double d)
{
return new MoneyAmount((decimal)d);
}
(You'll need one for every type you want to allow implicit casts)
Another one:
int i = 4;
MoneyAmount m = (MoneyAmount)i;
This is done with an explicit cast operator overload.
public static explicit operator MoneyAmount(double d)
{
return new MoneyAmount((decimal)d);
}
(Again, 1 for every type you want to allow explicit casts)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.