【问题标题】:Decimal ToString() conversion issue in C#C# 中的十进制 ToString() 转换问题
【发布时间】:2013-05-15 10:21:11
【问题描述】:

当我尝试将decimal? 转换为string 时遇到问题。情景是

decimal decimalValue = .1211;
string value = (decimalValue * 100).ToString();

当前结果:值 = 12.1100

预期结果:值 = 12.11

请告诉我,这可能是什么原因。

【问题讨论】:

  • 原因可能是系统默认的十进制数字格式。
  • 如果它们不为零,您是否希望它显示多于两位的小数?也就是说,如果你有.12113405,你会希望它显示为12.113405?
  • 正是我的想法:它只是尾随零,还是您希望始终限制为 2 位小数?在前一种情况下,没有一个答案能提供好的答案。
  • 想知道原因,为什么 toString() 方法是加了两个额外的零。

标签: c# string decimal


【解决方案1】:

Decimal 保留Decimal 数字中的任何尾随零。如果您想要两位小数:

decimal? decimalValue = .1211m;
string value = ((decimal)(decimalValue * 100)).ToString("#.##")

http://msdn.microsoft.com/en-us/library/0c899ak8.aspx

string value = ((decimal)(decimalValue * 100)).ToString("N2")

http://msdn.microsoft.com/en-us/library/dwhawy9k.aspx

来自System.Decimal

十进制数是浮点数 由一个符号组成的值,a 数字值,其中每个数字 值范围从 0 到 9,a 比例因子,表示 浮点小数点的位置 将积分和 数值的小数部分。

十进制的二进制表示 值由一个 1 位符号组成,一个 96 位整数和缩放 用于划分 96 位的因子 整数并指定它的哪一部分 是一个小数。缩放 factor 隐含地是数字 10, 提高到从 0 的指数 到 28. 因此,二进制 十进制值的表示是 形式为 ((-296 到 296) / 10(0 到 28)),其中 -296-1 等于 MinValue,并且 296-1 等于 最大值。

缩放因子还保留任何 十进制数中的尾随零。 尾随零不影响 十进制数的值 算术或比较操作。 但是,>>尾随零可以是 ToString 方法显示,如果 应用了适当的格式字符串

备注:

  1. 十进制乘法需要转换为十进制,因为Nullable<decimal>.ToString 没有格式提供程序
  2. 正如 Chris 指出的那样,您需要处理 Nullable<decimal>null 的情况。一种方法是使用Null-Coalescing-Operator

    ((decimal)(decimalValue ?? 0 * 100)).ToString("N2")
    

Jon Skeet 的这篇文章值得一读:

Decimal floating point in .NET(如果您不耐烦,请寻找保持零

【讨论】:

  • 强制转换为decimal 将抛出带有此代码的InvalidOperationException,而Pushkar 的原始代码将生成一个空字符串。不过在这种情况下可能不相关。
  • 对不起,蒂姆,我的意思是当 decimalValuenull 时它会抛出。
  • 感谢您的回复。我知道,可以通过指定格式化程序来解决,但我想知道为什么 toString() 方法会添加额外的零。
  • @Pushkar:你读过我引用的 msdn 链接吗? “缩放因子还保留 Decimal 数字中的任何尾随零……如果应用了适当的格式字符串,ToString 方法可以显示尾随零” 您的原始小数点有 4 个小数位,因此ToString 揭示了它们。顺便说一句,这里解释了为什么记住尾随零的数量很有用:stackoverflow.com/a/2996821/284240
【解决方案2】:

由于您使用Nullable<T> 作为您的decimalNullable<T>.ToString() 方法没有可用于格式化的重载参数。

您可以将其显式转换为decimal,并且可以使用.ToString() 方法进行格式化。

只需在您的.ToString() 方法中使用"0.00" 格式即可。

decimal? decimalValue = .1211M;
string value = ((decimal)(decimalValue * 100)).ToString("0.00");
Console.WriteLine(value);

输出将是;

12.11

这是DEMO

作为替代方案,您可以使用Nullable<T>.Value 而不进行任何对话;

string value = (decimalValue * 100).Value.ToString("0.00");

查看Custom Numeric Format Strings了解更多信息

【讨论】:

  • 强制转换为decimal 将使用此代码抛出InvalidOperationException,而Pushkar 的原始代码将生成一个空字符串。不过在这种情况下可能不相关。
  • @ChrisSinclair 不,在这种情况下它不会抛出任何异常。
  • 当我在 LinqPad 中逐字运行代码时会这样。编辑:抱歉,我的意思是当decimalValuenull。抱歉,我忘了实际那个。
  • 对不起,Soner,当decimalValue 为空时,我忘了写那是针对null 的情况。
  • 不需要强制转换和额外的括号,Nullable<T> 具有属性 Value,它将返回 T 或在本例中为 decimal
【解决方案3】:

或者,您可以指定格式“F2”,如下所示:string val = decVal.ToString("F2"),因为这指定了 2 个小数位。

【讨论】:

    【解决方案4】:

    使用fixed-point ("F) format specifier

       string value = (decimalValue * 100).ToString("F");
    

    默认精度说明符基于 NumberFormatInfo.NumberDecimalDigits 属性的值,默认值为 2。因此,如果在 "F" 之后不指定数字,则默认指定两位小数.

    F0 - No decimal places
    F1 - One decimal place
    

    【讨论】:

      【解决方案5】:

      如果您不想限制到一定数量的小数位数:

      decimal? decimalValue = .1211;
      string value = decimalValue == null 
                     ? "0"
                     : decimalValue == 0
                     ? "0"
                     : (decimalValue * 100).ToString().TrimEnd('0');
      

      这将修剪字符串的任何(如果有的话)尾随零,并且如果decimalValue 为空,则还返回“0”。如果值为 0,则返回“0”而不修剪。

      【讨论】:

        【解决方案6】:
        String.Format("{0:0.00}", decimalValue * 100);
        

        您可以使用.Format() 替代.ToString("0.00")。

        【讨论】:

          【解决方案7】:

          由于decimal? 没有ToString(string format) 重载,最简单的方法是使用String.Format,这将提供与decimalValuenull 情况一致的结果(导致空字符串)与您的原始代码相比:

          string value = String.Format("{0:#.##}", decimalValue * 100);
          

          但是对于您不清楚的其他数字还有其他一些注意事项。

          如果您有一个不产生大于 0 的值的数字,它是否显示前导零?也就是说,对于0.001211,它是显示为0.12 还是.12?如果你想要前导零,请改用它(注意从 #.##0.## 的变化):

          string value = String.Format("{0:0.##}", decimalValue * 100);
          

          如果您有超过 2 个有效小数位,您希望显示这些位吗?所以如果你有.12113405,它会显示为12.113405吗?如果是这样使用:

          string value = String.Format("{0:#.############}", decimalValue * 100);
          

          (老实说,我认为一定有一个更好的格式化字符串比那个,尤其是它只支持12位小数)

          当然,如果您想要两个前导零多个小数位,只需将以上两者结合起来:

          string value = String.Format("{0:0.############}", decimalValue * 100);
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-11-30
            • 1970-01-01
            • 1970-01-01
            • 2011-02-04
            • 1970-01-01
            • 2021-01-03
            相关资源
            最近更新 更多