questions/43293914/serialize-listlinkedlistnodeobject-using-json-net

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.Runtime.Serialization;
using System.Data;
using System.ComponentModel;
using System.Globalization;
using System.Collections.Specialized;
using System.Web.Routing;
using System.Net.Mail;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
using System.Net;
using System.Runtime.Serialization.Formatters;

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

    // https://stackoverflow.com/questions/43293914/serialize-listlinkedlistnodeobject-using-json-net
    public class LinkedListNodeListConverter<T> : JsonConverter
    {
        public override bool CanConvert(Type objectType)
        {
            return typeof(List<LinkedListNode<T>>).IsAssignableFrom(objectType);
        }

        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            if (reader.TokenType == JsonToken.Null)
                return null;
            var list = (existingValue as IList<LinkedListNode<T>> ?? (IList<LinkedListNode<T>>)serializer.ContractResolver.ResolveContract(objectType).DefaultCreator());
            var table = serializer.Deserialize<LinkedListNodeOrderTable<T>>(reader);
            foreach (var node in table.ToNodeList())
                list.Add(node);
            return list;
        }

        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            var list = (IList<LinkedListNode<T>>)value;
            var table = LinkedListNodeOrderTable<T>.FromList(list);
            serializer.Serialize(writer, table);
        }
    }

    class LinkedListNodeOrderTable<T>
    {
        public static LinkedListNodeOrderTable<T> FromList(IList<LinkedListNode<T>> nodeList)
        {
            if (nodeList == null)
                return null;
            try
            {
                var list = nodeList.Where(n => n != null).Select(n => n.List).Distinct().SingleOrDefault();
                var table = new LinkedListNodeOrderTable<T>(list);
                var dictionary = list == null ? null : list.EnumerateNodes().Select((n, i) => new KeyValuePair<LinkedListNode<T>, int>(n, i)).ToDictionary(p => p.Key, p => p.Value);
                table.Indices = nodeList.Select(n => (n == null ? -1 : dictionary[n])).ToList();
                return table;
            }
            catch (Exception ex)
            {
                throw new JsonSerializationException(string.Format("Failed to construct LinkedListNodeOrderTable<{0}>",  typeof(T)), ex);
            }
        }

        public LinkedListNodeOrderTable(LinkedList<T> List)
        {
            this.List = List;
        }

        public LinkedList<T> List { get; set; }

        public List<int> Indices { get; set; }

        public IEnumerable<LinkedListNode<T>> ToNodeList()
        {
            if (Indices == null || Indices.Count < 1)
                return Enumerable.Empty<LinkedListNode<T>>();
            var array = List == null ? null : List.EnumerateNodes().ToArray();
            return Indices.Select(i => (i == -1 ? null : array[i]));
        }
    }

    public static class LinkedListExtensions
    {
        public static IEnumerable<LinkedListNode<T>> EnumerateNodes<T>(this LinkedList<T> list)
        {
            if (list == null)
                yield break;
            for (var node = list.First; node != null; node = node.Next)
                yield return node;
        }
    }

    class TestClass
    {
        public static void Test()
        {
            TestFix(new List<LinkedListNode<string>>() { null, null, null });

            var l = new LinkedList<string>();
            l.AddLast("Kuku");
            l.AddLast("Riku");
            l.AddLast("Ok");
            var lst = new List<LinkedListNode<string>>();
            lst.Add(l.First);
            lst.Add(l.First.Next);
            lst.Add(l.Last);

            TestFix(lst);

            lst.Add(l.Last);
            lst.Add(null);
            lst.Add(l.First);
            TestFix(lst);

            Console.WriteLine("Done.");
        }

        public static void TestFix(List<LinkedListNode<string>> lst)
        {
            var settings = new JsonSerializerSettings
            {
                Converters = { new LinkedListNodeListConverter<string>() },
            };
            string json = JsonConvert.SerializeObject(lst, Formatting.Indented, settings);
            Console.WriteLine("Serialized JSON: ");
            Console.WriteLine(json);

            var lst2 = JsonConvert.DeserializeObject<List<LinkedListNode<string>>>(json, settings);

            var json2 = JsonConvert.SerializeObject(lst2, Formatting.Indented, settings);
            Console.WriteLine("Deserialized and re-serialized JSON: ");
            Console.WriteLine(json2);

            Assert.IsTrue(JToken.DeepEquals(JToken.Parse(json), JToken.Parse(json2)));
            Assert.IsTrue(lst.Select(n => n == null ? null : n.Value).SequenceEqual(lst2.Select(n => n == null ? null : n.Value)));

            Console.Write("Node list serialied and deserialize successfully.\n");
        }
    }

    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("Environment version: " + Environment.Version);
            Console.WriteLine("Json.NET version: " + typeof(JsonSerializer).Assembly.FullName);
            Console.WriteLine("");
	
			TestClass.Test();
		}
	}
;