十进制数据类型在需要显示时会去掉末尾的零。

12
我正在开发的一个网页应用程序(由另一名开发者编写)存在一个十进制变量,在小数点后面会丢失两个零。但如果最后两位包含大于0或组合的数字,则不会丢失尾随2位数字。这个值来自一个文本文件。

例如,文本值为:261.00 , 十进制变量(TotalDue)是:261。在调试时,当我将鼠标悬停在“TotalDue”上时,该值显示为261,并且当我展开调试器时,它读取“261M”:
decimal TotalDue = Convert.ToDecimal(InputRow.Substring(260, 12));

我已经尝试将它作为一个字符串输入(但最初仍然显示为“261”,而不是261.00),然后按照以下各种方式进行转换。 什么都没用!

string TotalDue = InputRow.Substring(260, 12);

strTotalDue = String.Format("{0:F2}", TotalDue);

strTotalDue = String.Format("{0:N2}", TotalDue);

strTotalDue = String.Format(TotalDue, "0.00");

strTotalDue = TotalDue.ToString("G29");  

strTotalDue = String.Format("{0:0.00}", TotalDue);

strTotalDue = TotalDue.ToString("N2");//used this one with decimal data type

我错过了什么?文本文件的数据起源是否很重要?它起源于一个Access数据库。

更新:今天(12/1/15)我意识到我从未标记答案,因为我最终放弃了原始代码并在C#.net中重写了它。我将标记Cole Campbell的答案为正确答案,因为他的话语(“以一种向其提供有关输入精度的足够数据来构造十进制数”)促使我想出了解决方案,即操纵传入的数据。我是用一个方法来做到这一点的——下面只显示了重要部分(AmtDue)。提醒一下,传入的数据格式为“261.00”(例如,AmtDue = 261.00):

string AmtDue = Convert.ToString(AmountDue).Replace(".", "");           
string finalstring =  ("0000000000" + AmtDue).Substring(AmtDue.Length);

不知道这个代码通过哪个流程,很难给出建议 - 你能展示一下相关的代码吗?否则,我只能建议使用 string.Format - 不过你已经尝试过了。 - Grahame A
正如其他人在(正确的)答案中提到的那样,您需要使用“D2”字符串格式。 “N2”会在小数点左侧填充。 - BTownTKD
D2出问题了,伙计们。 - SergeyS
看看 Cole Campbell 的回答,非常有趣! - SergeyS
4个回答

20

哈哈.. 10个赞,然后你发现这行不通)) - SergeyS
@SergeyS:是的,我很惊讶没有人记得它。我只是出于好玩而检查了一下,并认为Ideone是原因(没有其他可用的IDE)。但是,“0.00”可以工作。 - Tim Schmelter
1
Cole Campbell的回答真的很有趣!Decimal.ToString在很大程度上取决于十进制数的初始化方式,因此表现出截然不同的行为。 - SergeyS
@TimSchmelter: 因为我正在使用带有字段TotalDue?的类(DTO),所以我需要将这个格式化的字符串转换回decimal?,再次删除尾随的零 :( - RobertKing
@Rohaan:DecimalDecimal?只是存储值的数据类型,没有格式。你只能在字符串中格式化一个十进制数。 - Tim Schmelter
显示剩余3条评论

18
你的第一个示例中丢失零的原因很可能与创建Decimal实例的方式有关。 Decimal包含一个缩放因子,它影响ToString()的工作方式,并且根据构造Decimal的方式设置不同的缩放因子。
这段代码:
var d1 = Decimal.Parse("261.00");
var d2 = new Decimal(261.00);
var d3 = 261.00m;
Console.WriteLine(d1);
Console.WriteLine(d2);
Console.WriteLine(d3);

生成以下结果:

261.00
261
261.00

如果您想保留尾随的零,则需要以一种能够提供关于输入精度的足够数据的方式构造Decimal

请记住,正如其他答案所指出的那样,调试器提供的字符串并不一定与ToString()生成的字符串相同。


Cole,你的解释非常清晰易懂,写得也很好,但是它仍然没有解决我的问题...不过我还在尝试中...只是想说谢谢你花时间解释! - Doreen
非常有趣。它仅适用于 .ToString() 而没有任何类型格式(用于隐式转换),但这绝对不是我所期望的行为。 - Bobson

5
您在调试器中看到的数字与其实际显示方式没有任何关联。261M是正确的——它是以十进制("M"代表"Money",即十进制)格式存储的"261"值。
尝试使用这里的数字格式化代码。"F2"是您需要的。

D2不起作用。你需要先尝试,然后才能回答。 - SergeyS
@SergeyS - 你是对的。这就是我只是根据快速检查文档和记忆所得到的结果。已将其更改为F2。 - Bobson

3
我确定你可以使用谷歌,并且可能已经找到了这个链接,但是这里提供给你参考:String Formatting Doubles 看起来你已经尝试使用 strTotalDue = String.Format("{0:0.00}", TotalDue);,所以我不确定还有什么问题。
然而,如果没有更多上下文信息,我们就无法解决这个问题。

每个人的评论都很有帮助,谢谢!我可以在控制台中让示例运行,但无法在应用程序中运行。问题可能出现在代码的其他位置,我还无法确定。我展示的代码行是外部文本文件进入的第一个入口点。无论我使用什么数据类型,var、string、decimal,文本都会以261M的形式输入。 - Doreen
如果来自Access的原始数据为261M,则需要在演示层剥离M并进行格式化,或在Access中格式化字符串。尽管我怀疑您的值末尾的m是为了格式化目的而包含的,请参见Cole Campbells的答案。如果它有效,请确保接受他的答案! - Grahame A
1
@Doreen - 根据我的回答,在调试器中查看“261M”是完全正常的。但如果你读取的数据是一个字符串,表示为“261M”,那么这就是一个数据问题。你能否查看原始数据以了解它的实际情况? - Bobson
我已经了解到TotalDue变量在一个外部的VB类中被使用,并且被转换为浮点数,如下所示: - Doreen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接