Question41945353 newtonsoft-jsonconvert-complex-number-issue

CSharp · Console

/Program.cs

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.IO;
using System.Threading;
using System.Collections.ObjectModel;
using System.Reflection;
using System.ComponentModel;
using System.Globalization;
using System.Web.Routing;
using System.Net.Mail;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
using System.Net;
using System.Numerics;

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;


//     // https://stackoverflow.com/questions/41945353/newtonsoft-jsonconvert-complex-number-issue


    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);
        }
    }

    public class Calculation
    {
        public Electrical Electrical { get; set; }
    }

    public class Electrical
    {
        public Impedance Impedance { get; set; }
    }

    public class Impedance
    {
        public Complex Z0 { get; set; }
        public Complex Z1 { get; set; }
    }

    public class TestClass
    {
        public static void Test()
        {
            {
                Console.WriteLine("Testing ComplexArrayConverter...");
                var settings = new JsonSerializerSettings
                {
                    Converters = { new ComplexArrayConverter() },
                };
                Test(settings);
                Console.WriteLine("");
            }
            {
                Console.WriteLine("Testing ComplexMathJSConverter...");
                var settings = new JsonSerializerSettings
                {
                    Converters = { new ComplexMathJSConverter() },
                };
                Test(settings);
                Console.WriteLine("");
            }
            {
                Console.WriteLine("Testing ComplexObjectConverter...");
                var settings = new JsonSerializerSettings
                {
                    Converters = { new ComplexObjectConverter() },
                };
                Test(settings);
                Console.WriteLine("");
            }
            {
                Console.WriteLine("Testing ComplexObjectConverter with CamelCasePropertyNamesContractResolver...");
                var settings = new JsonSerializerSettings
                {
                    Converters = { new ComplexObjectConverter() },
                    ContractResolver = new CamelCasePropertyNamesContractResolver(),
                };
                Test(settings);
                Console.WriteLine("");
            }
        }

        public static void Test(JsonSerializerSettings settings)
        {
            var calculation = new Calculation
            {
                Electrical = new Electrical
                {
                    Impedance = new Impedance
                    {
                        Z0 = new Complex(0.0017923713150000001, 0),
                        Z1 = new Complex(3, 4),
                    }
                }
            };
            var json = JsonConvert.SerializeObject(calculation, settings);
            Console.WriteLine("Serialized JSON: ");
            Console.WriteLine(json);

            var calculation2 = JsonConvert.DeserializeObject<Calculation>(json, settings);
            var json2 = JsonConvert.SerializeObject(calculation, settings);
            Console.WriteLine("Deserialized and reserialized JSON: ");
            Console.WriteLine(json2);

            Assert.IsTrue(calculation.Electrical.Impedance.Z0 == calculation.Electrical.Impedance.Z0);
            Assert.IsTrue(calculation.Electrical.Impedance.Z1 == calculation.Electrical.Impedance.Z1);

            Console.WriteLine("Z0 and Z1 were serialized and deserialized successfully.");
        }
    }

    public class AssertionFailedException : System.Exception
    {
        public AssertionFailedException() : base() { }

        public AssertionFailedException(string s) : base(s) { }
    }

    public static class Assert
    {
        public static void IsTrue(bool value)
        {
            if (value == false)
                throw new AssertionFailedException("failed");
        }
    }

	public class Program
	{
		public static void Main()
		{
            Console.WriteLine("Json.NET version: " + typeof(JsonSerializer).Assembly.FullName);
            Console.WriteLine("");

			TestClass.Test();
		}
	}
;