Newtonsoft JsonConvert 复数问题

Posted

技术标签:

【中文标题】Newtonsoft JsonConvert 复数问题【英文标题】:Newtonsoft JsonConvert Complex Number Issue 【发布时间】:2017-01-30 21:02:19 【问题描述】:

我在相当复杂的 DTO 上使用 Newtonsoft JsonConvert.SerializeObject 和 JsonConvert.DeserializeObject。其中,我有一些复数(System.Numerics)。除了复数之外,一切都完美无缺。

数字序列化得很好,结果是:


    ... lots of JSON here ...   
    "Electrical":      
        ... lots of JSON objects ... 
            "Z1": 
                "Real": 0.0017923713150000001,
                "Imaginary": 0.0,
                "Magnitude": 0.0017923713150000001,
                "Phase": 0.0
            ,
            "Z0": 
                "Real": 0.0017923713150000001,
                "Imaginary": 0.0,
                "Magnitude": 0.0017923713150000001,
                "Phase": 0.0
            
        
    ... lots of JSON .. here ...

问题出在反序列化中,返回的复数全是零,例如:

calculation.Electrical.Impedance.Z0
(0, 0)
    Imaginary: 0
    Magnitude: 0
    Phase: 0
    Real: 0
    m_imaginary: 0
    m_real: 0

任何有关如何解决此问题的建议都会很棒。

【问题讨论】:

您可能只需要实现一个自定义的JsonConverter 类。在此处查看答案以获取类似示例:***.com/questions/24051206/… 【参考方案1】:

Json.NET 和 JSON standard 都没有预定义的复数格式,因此 Json.NET 将序列化 Complex 的所有属性,生成您看到的输出。要获得只包含必要数据的干净 JSON,您需要编写一个 custom JsonConverterComplex 从 JSON 序列化到 JSON。

但是,应该使用什么格式?选项可能包括:

    作为数组:[0.0017923713150000001,0.0]。 作为具有"Real""Imaginary" 属性的对象:"Real":0.0017923713150000001,"Imaginary":0.0。 在math.js format:"mathjs":"Complex","re":0.0017923713150000001,"im":0.0

以下是每种格式的转换器:

public abstract class ComplexConverterBase : JsonConverter

    public override bool CanConvert(Type objectType)
    
        return objectType == typeof(Complex) || objectType == typeof(Complex?);
    


public class ComplexArrayConverter : ComplexConverterBase

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    
        if (reader.TokenType == JsonToken.Null)
            return null;
        var array = serializer.Deserialize<double[]>(reader);
        if (array.Length != 2)
        
            throw new JsonSerializationException(string.Format("Invalid complex number array of length 0", array.Length));
        
        return new Complex(array[0], array[1]);
    

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    
        var complex = (Complex)value;
        writer.WriteStartArray();
        writer.WriteValue(complex.Real);
        writer.WriteValue(complex.Imaginary);
        writer.WriteEndArray();
    


public class ComplexObjectConverter : ComplexConverterBase

    // By using a surrogate type, we respect the naming conventions of the serializer's contract resolver.
    class ComplexSurrogate
    
        public double Real  get; set; 
        public double Imaginary  get; set; 

        public static implicit operator Complex(ComplexSurrogate surrogate)
        
            if (surrogate == null)
                return default(Complex);
            return new Complex(surrogate.Real, surrogate.Imaginary);
        

        public static implicit operator ComplexSurrogate(Complex complex)
        
            return new ComplexSurrogate  Real = complex.Real, Imaginary = complex.Imaginary ;
        
    

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    
        if (reader.TokenType == JsonToken.Null)
            return null;
        return (Complex)serializer.Deserialize<ComplexSurrogate>(reader);
    

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    
        serializer.Serialize(writer, (ComplexSurrogate)(Complex)value);
    


public class ComplexMathJSConverter : ComplexConverterBase

    // Serialize in math.js format
    // http://mathjs.org/docs/core/serialization.html
    // By using a surrogate type, we respect the naming conventions of the serializer's contract resolver.
    class ComplexSurrogate
    
        [JsonProperty(Order = 1)]
        public double re  get; set; 
        [JsonProperty(Order = 2)]
        public double im  get; set; 
        [JsonProperty(Order = 0)]
        public string mathjs  get  return "Complex";  

        public static implicit operator Complex(ComplexSurrogate surrogate)
        
            if (surrogate == null)
                return default(Complex);
            return new Complex(surrogate.re, surrogate.im);
        

        public static implicit operator ComplexSurrogate(Complex complex)
        
            return new ComplexSurrogate  re = complex.Real, im = complex.Imaginary ;
        
    

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    
        if (reader.TokenType == JsonToken.Null)
            return null;
        return (Complex)serializer.Deserialize<ComplexSurrogate>(reader);
    

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    
        serializer.Serialize(writer, (ComplexSurrogate)(Complex)value);
    

然后,你将序列化如下:

var settings = new JsonSerializerSettings

    // Add a complex converter to the Converts array.  
    // Use one of ComplexArrayConverter, ComplexMathJSConverter and ComplexObjectConverter
    Converters =  new ComplexArrayConverter() ,
;
var json = JsonConvert.SerializeObject(calculation, settings);

要在全局设置中使用转换器,请参阅here 用于 Web API 或 here 直接调用序列化程序。

示例fiddle。

【讨论】:

dbc,感谢您清晰详细的解释。它工作得很好。经过数小时的搜索,您的回答对我们很有帮助。

以上是关于Newtonsoft JsonConvert 复数问题的主要内容,如果未能解决你的问题,请参考以下文章

JsonConvert 在 Newtonsoft.Json Asp.net MVC C# 中不起作用

Newtonsoft.Json.JsonConvert 序列化与反序列化

找不到方法 Void Newtonsoft.Json.JsonConvert.set_DefaultSettings

Newtonsoft.Json.JsonConvert 从同一个类中序列化和反序列化

找不到JsonConvert.cs

json Xml 互转