Newtonsoft JsonConvert复数问题

时间:2017-01-30 21:02:20

标签: c# json json.net complex-numbers

我在相当复杂的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

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

1 个答案:

答案 0 :(得分:1)

Json.NET和JSON standard都没有复杂数字的预定义格式,因此Json.NET将序列化Complex的所有属性,生成您看到的输出。要仅使用必要的数据来获取干净的JSON,您需要编写一个custom JsonConverter,将Complex序列化为JSON。

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

  1. 作为数组:[0.0017923713150000001,0.0]
  2. 作为具有"Real""Imaginary"属性的对象:{"Real":0.0017923713150000001,"Imaginary":0.0}
  3. math.js format{"mathjs":"Complex","re":0.0017923713150000001,"im":0.0}
  4. 以下是每种格式的转换器:

    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 for Web API或here

    示例fiddle