【问题标题】:How to set FloatParseHandling.Decimal for custom JsonConverter?如何为自定义 JsonConverter 设置 FloatParseHandling.Decimal?
【发布时间】:2020-01-07 09:17:28
【问题描述】:

如何为自定义 JsonConverter 设置 FloatParseHandling.Decimal?

我们有一个结构 DecimalDbValue,它在内部只保存一个十进制字段,我想对其所有类型进行反序列化。

它使用一个幻数(decimal.MinValue)来表示一个“空”值。它是在 .net 2.0 之前创建的,具有可为空的值类型!

这是我们结构体的简化版本::

    [Serializable]
    [JsonConverter(typeof(DecimalDbValueJsonConverter))]
    public struct DecimalDbValue : ISerializable
    {
        private readonly Decimal _decValue;

        public DecimalDbValue(
            decimal init)
        {
            _decValue = init;
        }

        [JsonConstructor]
        public DecimalDbValue(
            decimal? init)
        {
            if (init.HasValue)
                _decValue = init.Value;
            else
                _decValue = decimal.MinValue;
        }

        private DecimalDbValue(
            SerializationInfo objSerializationInfo,
            StreamingContext objStreamingContext)
        {
            _decValue = objSerializationInfo.GetDecimal("value");
        }

        public bool IsNotNull
        {
            get
            {
                return !IsNull;
            }
        }

        public bool IsNull
        {
            get
            {
                return _decValue.Equals(Decimal.MinValue);
            }
        }

        public Decimal Value
        {
            get
            {
                return _decValue;
            }
        }

        public void GetObjectData(
            SerializationInfo info,
            StreamingContext context)
        {
            info.AddValue("value", _decValue);
        }
}

我创建了一个 JsonConverter:

    class DecimalDbValueJsonConverter : JsonConverter
    {
        public override bool CanConvert(Type objectType)
        {
            return typeof(DecimalDbValue) == objectType;
        }

        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            var value = reader.Value == null ? (decimal?)null : Convert.ToDecimal(reader.Value);
            return new DecimalDbValue(value);
        }

        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            var dbValue = (DecimalDbValue)value;
            if (dbValue.IsNull)
                writer.WriteNull();
            else
                writer.WriteValue(dbValue.Value);
        }
    }

并在 DecimalDbValue 结构上设置属性 [JsonConverter(typeof(DecimalDbValueJsonConverter))]

我添加了一个测试:

        [Test]
        public void TestMaxDecimalDbValue()
        {
            var s = new DecimalDbValue(decimal.MaxValue);
            var json = JsonConvert.SerializeObject(s, Formatting.Indented);
            var x = JsonConvert.DeserializeObject<DecimalDbValue>(json);

            Assert.AreEqual(s, x);
        }

但它会抛出: System.OverflowException : Value was either too large or too small for a Decimal.

如何为 JsonConverter 设置 FloatParseHandling.Decimal?如何使它也适用于MaxValue?有没有其他办法?

实际上我想让它像decimal?(可为空的十进制)一样序列化/反序列化

谢谢

【问题讨论】:

  • 哪一行导致异常?请分享堆栈跟踪和DecimalDbValue 类。另外,您使用的是哪个 .NET 版本?
  • 本帖中的回答应该可以帮助您解决问题Force decimal type in class definition during serialization
  • @PavelAnikhouski Convert.ToDecimal(reader.Value); ReadJson 内导致异常。我们正在使用 .net 4.7.2。我不能发布整个结构,它非常冗长。在ReadJson 内的Convert.ToDecimal(reader.Value) 上抛出异常当尝试其他解决方案时serializer.Populate(reader, existingValue); 抛出Newtonsoft.Json.JsonSerializationException : Unexpected initial token 'Float' when populating object. Expected JSON object or array. Path '', line 1, position 31.
  • 请将此信息添加到您的问题中。如果没有DecimalDbValue 属性、IsNullValue,我至少无法重现您的问题
  • @toebens - 如果DecimalDbValue根对象 那么FloatParseHandlingConverter 将不起作用,因为它需要应用于容器类型。将其应用于DecimalDbValue 本身将不起作用,因为在调用ReadJson() 时,十进制值已经作为double 读入。在这种情况下,您需要显式设置JsonSerializerSettings.FloatParseHandling。但是当不是根对象时,将FloatParseHandlingConverter 应用于容器将起作用。见dotnetfiddle.net/BmgKYj。你真的用DecimalDbValue作为你的根吗?

标签: c# .net json.net jsonconverter


【解决方案1】:

这似乎是不可能的。

因此我完全删除了 JsonConverter。

在结构上设置这个属性:

[JsonObject(MemberSerialization.OptIn)]

以及构造函数上的this:

 [JsonConstructor]
    public DecimalDbValue(
        decimal? init) //IMPORTANT: if you change the name of init - rename the JsonProperty below too - you might break all existing json out there thou!

以及get属性上的这个:

[JsonProperty("init")]
    public Decimal Value
    {
        get
        {
            return _decValue;
        }
    }

不幸的是,这会使 json 膨胀:

{
    "init": 79228162514264337593543950335.0
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-09-25
    • 1970-01-01
    • 1970-01-01
    • 2011-12-23
    • 1970-01-01
    • 2019-12-28
    • 2020-09-07
    • 1970-01-01
    相关资源
    最近更新 更多