实现 IConvertible 的自定义数据类型的反序列化问题

Ani*_*B.M 3 c# json json.net

我有一个类ChargesDetail,正在尝试反序列化 json,如下所示。这里我使用的数据类型是Amount.

public class ChargesDetail
{
   public double DiscountRate { get; set; }
   public Amount DiscountAmount { get; set; }
}

public class Amount:IConvertible 
{
    private double _val = 0;
    private int _decimal = 5;

    public Amount()
    {
    }

    public Amount(double amount): this()            
    {
       // this.Value = amount;
        _val = Math.Round(amount, _decimal);
    }

    #region IConvertible Members

    // Implementation snipped

    #endregion
}
Run Code Online (Sandbox Code Playgroud)

我的 JSON 看起来像:

{ "DiscountRate":0.0, "DiscountAmount":0.0 }
Run Code Online (Sandbox Code Playgroud)

我正在尝试像这样反序列化:

T result = JsonConvert.DeserializeObject<ChargesDetail>(json);
Run Code Online (Sandbox Code Playgroud)

它给了我一个例外,例如:

从“System.Double”到“Amount”的无效转换。

在 System.Convert.DefaultToType(IConvertible value, Type targetType, IFormatProvider provider) at System.Double.System.IConvertible.ToType(Type type, IFormatProvider provider) at System.Convert.ChangeType(Object value, Type conversionType, IFormatProvider provider) at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.EnsureType(JsonReader reader, Object value, CultureInfo culture, JsonContract contract, Type targetType)

如何将 json 反序列化为这种自定义数据类型?

  • 我无法删除 IConvertible,因为它在某些计算中抛出 System.StackOverflowException。
  • 我无法将 Amount 类型更改为 double 类型,因为在“Amount”类中有 100 多个相同类型的属性并在进行计算。

dbc*_*dbc 5

由于您的问题表明您正在使用,您可以Amount使用自定义JsonConverter将您的序列化为单个十进制值:

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

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        // Would decimal be more appropriate than double?
        var value = serializer.Deserialize<double?>(reader);
        if (value == null)
            return null;
        return new Amount(value.Value);

    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        writer.WriteValue(((Amount)value).Value);
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,您可以将其应用到您的模型中,如下所示:

[JsonConverter(typeof(AmountConverter))]
public class Amount : IConvertible
{
    private double _val = 0;
    private int _decimal = 5;

    public double Value { get { return _val; } }

    public Amount()
    {

    }

    public Amount(double amount)
        : this()
    {
        // this.Value = amount;
        _val = Math.Round(amount, _decimal);
    }

    #region IConvertible Members
    #endregion
}
Run Code Online (Sandbox Code Playgroud)

或者在JsonSerializerSettings.Converters序列化和反序列化时加入:

var settings = new JsonSerializerSettings
{
    Converters = { new AmountConverter() },
};
var = JsonConvert.DeserializeObject<T>(json, settings);
Run Code Online (Sandbox Code Playgroud)

笔记:

  1. 如果Amount旨在表示货币数量,您可能会考虑decimaldouble

    但是如果你这样做了,你将需要切换到FloatParseHandling.Decimal更高的级别,以防止在解析JsonTextReader. 这可以通过例如JsonSerializerSettings.FloatParseHandling全局设置或通过在序列化期间FloatParseHandlingConverter这个答案中抓取到类定义中的强制十进制类型并将其应用于父类来完成,ChargesDetail如下所示:

    [JsonConverter(typeof(FloatParseHandlingConverter), FloatParseHandling.Decimal)]
    public class ChargesDetail
    {
        public decimal DiscountRate { get; set; }
        public Amount DiscountAmount { get; set; }
    }
    
    Run Code Online (Sandbox Code Playgroud)

演示小提琴在这里