首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >将小数序列化为JSON,如何四舍五入?

将小数序列化为JSON,如何四舍五入?
EN

Stack Overflow用户
提问于 2012-09-05 21:53:55
回答 4查看 35.3K关注 0票数 27

我有一节课

代码语言:javascript
复制
public class Money
{
    public string Currency { get; set; }
    public decimal Amount { get; set; }
}

并希望将其序列化为JSON。如果我使用JavaScriptSerializer,我会得到

代码语言:javascript
复制
{"Currency":"USD","Amount":100.31000}

由于我必须符合JSON数量最多两位小数的要求,我觉得应该可以以某种方式改变JavaScriptSerializer序列化小数字段的方式,但我找不到方法。您可以在构造函数中传递SimpleTypeResolver,但据我所知,它只对类型有效。可以通过RegisterConverters(...)添加的JavaScriptConverter似乎是为Dictionary量身定做的。

我想要一个

代码语言:javascript
复制
{"Currency":"USD","Amount":100.31}

在我序列化之后。此外,更改为double也是不可能的。我可能需要进行一些舍入(100.311应该变成100.31)。

有人知道怎么做吗?是否有JavaScriptSerializer的替代方案可以让您更详细地控制序列化?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2012-09-05 22:36:04

在第一种情况下,000没有坏处,值仍然是相同的,并且将被反序列化为完全相同的值。

在第二种情况下,JavascriptSerializer不会对您有所帮助。JavacriptSerializer不应该更改数据,因为它将数据序列化为众所周知的格式,它不提供成员级别的数据转换(但它提供自定义对象转换器)。您需要的是转换+序列化,这是一个分两个阶段的任务。

两个建议:

1)使用DataContractJsonSerializer:添加另一个舍入值的属性:

代码语言:javascript
复制
public class Money
{
    public string Currency { get; set; }

    [IgnoreDataMember]
    public decimal Amount { get; set; }

    [DataMember(Name = "Amount")]
    public decimal RoundedAmount { get{ return Math.Round(Amount, 2); } }
}

2)克隆取值对象:

代码语言:javascript
复制
public class Money 
{
    public string Currency { get; set; }

    public decimal Amount { get; set; }

    public Money CloneRounding() {
       var obj = (Money)this.MemberwiseClone();
       obj.Amount = Math.Round(obj.Amount, 2);
       return obj;
    }
}

var roundMoney = money.CloneRounding();

我猜json.net也不能做到这一点,但我不能百分之百确定。

票数 4
EN

Stack Overflow用户

发布于 2014-09-23 23:26:47

到目前为止,我对实现这一目标的所有技术并不完全满意。JsonConverterAttribute似乎是最有前途的,但我不能忍受硬编码的参数和各种选项组合的大量转换器类。

因此,我提交了一个PR,它添加了向JsonConverter和JsonProperty传递各种参数的功能。它已经被上游接受了,我希望在下一个版本中(6.0.5之后的下一个版本)

然后你可以这样做:

代码语言:javascript
复制
public class Measurements
{
    [JsonProperty(ItemConverterType = typeof(RoundingJsonConverter))]
    public List<double> Positions { get; set; }

    [JsonProperty(ItemConverterType = typeof(RoundingJsonConverter), ItemConverterParameters = new object[] { 0, MidpointRounding.ToEven })]
    public List<double> Loads { get; set; }

    [JsonConverter(typeof(RoundingJsonConverter), 4)]
    public double Gain { get; set; }
}

有关示例,请参阅CustomDoubleRounding()测试。

票数 20
EN

Stack Overflow用户

发布于 2014-06-12 16:51:20

为了便于将来参考,这可以通过创建自定义JsonConverter在Json.net中很好地实现

代码语言:javascript
复制
public class DecimalFormatJsonConverter : JsonConverter
{
    private readonly int _numberOfDecimals;

    public DecimalFormatJsonConverter(int numberOfDecimals)
    {
        _numberOfDecimals = numberOfDecimals;
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var d = (decimal) value;
        var rounded = Math.Round(d, _numberOfDecimals);
        writer.WriteValue((decimal)rounded);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue,
        JsonSerializer serializer)
    {
        throw new NotImplementedException("Unnecessary because CanRead is false. The type will skip the converter.");
    }

    public override bool CanRead
    {
        get { return false; }
    }

    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(decimal);
    }
}

如果您使用构造函数显式地在代码中创建序列化程序,这将很好地工作,但我认为用JsonConverterAttribute修饰相关属性会更好,在这种情况下,类必须有一个公共的、无参数的构造函数。我通过创建一个特定于我想要的格式的子类解决了这个问题。

代码语言:javascript
复制
public class SomePropertyDecimalFormatConverter : DecimalFormatJsonConverter
{
    public SomePropertyDecimalFormatConverter() : base(3)
    {
    }
}

public class Poco 
{
    [JsonConverter(typeof(SomePropertyDecimalFormatConverter))]
    public decimal SomeProperty { get;set; }
}

自定义转换器是从Json.NET documentation派生而来的。

票数 10
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/12283070

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档