c# - Newtonsoft JsonConvert 复数问题

标签 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

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

最佳答案

Json.NET 和 JSON standard 都不是具有复数的预定义格式,因此 Json.NET 将序列化 Complex 的所有属性,生成您看到的输出。要仅使用必要的数据获取干净的 JSON,您需要编写 custom JsonConverterComplex 与 JSON 序列化。

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

  1. 作为数组:[0.0017923713150000001,0.0]
  2. 作为具有 "Real""Imaginary" 属性的对象:{"Real":0.0017923713150000001,"Imaginary":0.0} .
  3. math.js format :{"mathjs":"复杂","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 .

关于c# - Newtonsoft JsonConvert 复数问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41945353/

相关文章:

c# - Bootstrap 模式中的 ASP.NET 按钮不触发点击事件

c# - 在 Caliburn Micro 中使用 Telerik RadWindow 和自定义 WindowManager 的问题

c# - asp.net core中间件无法捕获newtonsoft异常

c# - 反序列化包含另一个数组的字符串数组

c# - 使用 mvvm 在 xamarin 表单中的 View 之间传递数据

c# - 父面板点击事件

java - 使用 Google Storage 将图像上传/下载到 Google Compute Engine

java - 解析具有不同键的 JSON 对象

c# - Json.Net 反序列化以索引为名称的 JSON 对象

c# - 将 json 动态反序列化为传入的任何对象。 c#