C. McCoy IV C. McCoy IV - 1 month ago 12
C# Question

How to achieve ideal json serializing/deserializing in C# UWP?

Note: The question is restricted to C# UWP.

The Dream:



public static class Serializer {
// return json string
public string Serialize(object obj) { ??? }
// return T from json string
public T Deserialize<T>(string jsonString) { ??? }
}


Closest I've Come:



public static class Serializer
{
public static string Serialize(object obj, DataContractJsonSerializerSettings settings=null)
{
if (obj == null) {
throw new NullReferenceException();
}

settings = settings ?? new DataContractJsonSerializerSettings();
DataContractJsonSerializer jsonizer = new DataContractJsonSerializer(obj.GetType(), settings);
string jsonString = null;
using ( MemoryStream stream = new MemoryStream() )
{
jsonizer.WriteObject(stream, obj);
stream.Position = 0;
StreamReader sr = new StreamReader(stream);
jsonString = sr.ReadToEnd();
}
return jsonString;
}

public static T Deserialize<T>(string jsonString)
{
DataContractJsonSerializer jsonizer = new DataContractJsonSerializer(typeof(T));
T obj;
using (Stream stream = GenerateStreamFromString(jsonString))
{
obj = (T)jsonizer.ReadObject(stream);
}
return obj;
}

private static Stream GenerateStreamFromString(string s)
{
MemoryStream stream = new MemoryStream();
StreamWriter writer = new StreamWriter(stream);
writer.Write(s);
writer.Flush();
stream.Position = 0;
return stream;
}
}


The Problem



The partial solution I posted works in simple cases. However, it fails when the subtype of the object being deserialized is difficult (or impossible) to determine from the json string. For instance,

IList<Animal> animals = new List<Animal>();
animals.add(new Dog("Woofy"));
animals.add(new Cat("Fluffy"));

string json = Serializer.Serialize(animals);
IList<Animal> result = Serializer.Deserialize<List<Animal>>(json);
// ^ fails because subtype information was lost during serialization

bool succeeded = result.get(0).Name.Equals("Woofy") && result.get(1).Name.Equals("Fluffy");


What I'm Looking For:



An implementation of the skeleton specified in "The Dream" which passes the driver specified in "The Problem". Comments welcome.

Answer

The answer I arrived at:

using System;
using System.Collections.Generic;
using Newtonsoft.Json;

namespace SerializationDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            Dog dog = new Dog()
            {
                Name = "Woofy",
                HadWalkToday = true
            };
            Cat cat = new Cat()
            {
                Name = "Fluffy",
                ColorOfWhiskers = "Brown"
            };
            IList<Animal> animals = new List<Animal>()
            {
                dog,
                cat
            };

            string json = Serializer.Serialize(animals);
            IList<Animal> result = Serializer.Deserialize<List<Animal>>(json);

            bool serializerSuccessful = dog.Equals(result[0]) && cat.Equals(result[1]);
        }
    }

    public class Animal
    {
        public string Name { get; set; }

        public override bool Equals(object obj)
        {
            var animal = obj as Animal;
            return this.Name == animal.Name;
        }
    }

    public class Dog : Animal
    {
        public bool HadWalkToday { get; set; }

        public override bool Equals(object obj)
        {
            var dog = obj as Dog;
            return this.HadWalkToday == dog.HadWalkToday && base.Equals(obj);
        }
    }

    public class Cat : Animal
    {
        public string ColorOfWhiskers { get; set; }

        public override bool Equals(object obj)
        {
            var cat = obj as Cat;
            return this.ColorOfWhiskers == cat.ColorOfWhiskers && base.Equals(obj);
        }
    }

    public static class Serializer
    {
        private static readonly JsonSerializerSettings settings = new JsonSerializerSettings()
        {
            TypeNameHandling = TypeNameHandling.All,
            Formatting = Formatting.Indented
        };

        public static string Serialize(object obj)
        {
            if (obj == null)
            {
                throw new NullReferenceException();
            }

            string jsonString = JsonConvert.SerializeObject(obj, settings);
            return jsonString;
        }

        public static T Deserialize<T>(string jsonString)
        {
            T obj = JsonConvert.DeserializeObject<T>(jsonString, settings);
            return obj;
        }
    }
}
Comments