c#创建自定义“双”类型

时间:2016-07-05 08:34:39

标签: c# types double rounding

在我的应用程序中,我希望所有存储金额的属性都舍入到n小数位。

为了清晰代码,我宁愿拥有一个自定义类型MoneyAmount,我所有相应的字段都有,而不必在所有属性getter /中放入一个`Math.Round(value,n)' setter方法。

有没有一种巧妙的方法来实现这一目标?

我看到this post关于重载赋值运算符 - 这是建议的方法吗?

编辑: 鉴于多个视图,我发布了我在此处派生的完整代码:

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
}

2 个答案:

答案 0 :(得分:8)

我建议如下:

  1. 创建一个名为MoneyAmount的新结构。
  2. 它包含一个字段:A double
  3. 具有一个double参数的构造函数,此构造函数对该值进行舍入并将其分配给内部字段。
  4. 将您可能需要的成员/运算符添加到结构中,使其具有与double完全相同的操作,如+, - 等。还可以从/向其他类型转换/转换。每个操作都会生成一个带有舍入值的MoneyAmount的新实例。
  5. 还考虑实施接口IFormattableIComparableIConvertible
  6. 简短的例子:

    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...
    }
    

    我意识到:double有很多成员......

    使用这些运算符,可以使用以下代码:

    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.
    

    <强> 修改

    您可能希望实施的所有转换方法:

    • 明确的MoneyAmount - &gt; int
    • 明确的MoneyAmount - &gt;浮
    • 明确的MoneyAmount - &gt;双
    • 明确的MoneyAmount - &gt;十进制

    • 隐式int - &gt; MoneyAmount

    • 隐式浮动 - &gt; MoneyAmount
    • 隐含双重 - &gt; MoneyAmount
    • 隐式小数 - &gt; MoneyAmount

    您可能想要实施的所有数学运算:

    • MoneyAmount + MoneyAmount
    • MoneyAmount - MoneyAmount
    • MoneyAmount * MoneyAmount
    • MoneyAmount / MoneyAmount

    您可能想要实施的所有关系操作:

    • MoneyAmount == MoneyAmount
    • MoneyAmount!= MoneyAmount
    • MoneyAmount&gt; MoneyAmount
    • MoneyAmount&gt; = MoneyAmount
    • MoneyAmount&lt; MoneyAmount
    • MoneyAmount&lt; = MoneyAmount

    通过所有这些操作,您可以了解所有基础知识。

答案 1 :(得分:3)

这很快变大了。编写结构很容易,如@ MartinMulder的答案所示,但考虑到你需要重载多个运算符组合,以及包括一些隐式/显式转换。

数学与数学逻辑操作

请考虑您可能希望对MoneyAmount

进行数学运算
  • MoneyAmount + MoneyAmount
  • MoneyAmount + double
  • MoneyAmount + int
  • MoneyAmount + decimal

这是+运算符的4次重载。冲洗并重复-/*(以及可能%)。您还要重载<<===>>=。这就像30个运算符重载。唷!那就是很多静态方法。

public static MoneyAmount operator +(MoneyAmount d1, double d2) 
{
    return new MoneyAmount((decimal)(d1._value + d2));
}

明确/隐含的演员阵容

现在考虑代替此代码

MoneyAmount m = new MoneyAmount(1.234);

你想这样做:

MoneyAmount m = 1.234;

可以使用隐式强制转换运算符来实现。

public static implicit operator MoneyAmount(double d)
{
    return new MoneyAmount((decimal)d);
}

(对于你想允许隐式演员表的每种类型,你都需要一个)

另一个:

int i = 4;
MoneyAmount m = (MoneyAmount)i;

这是通过显式强制转换运算符重载完成的。

public static explicit operator MoneyAmount(double d)
{
    return new MoneyAmount((decimal)d);
}

(同样,对于您希望允许显式转换的每种类型都为1)