0

I have a problem with deserialized Dictionary. I can't cast objects from Dictionary to my type Remiza... I'm using Json.net and what I can see is that objects in Dictionary are JObject not Object and I can't cast them to my type. Here is my serialization/deserialization code:

    private static Dictionary<Type, List<Object>> _ekstensje = new Dictionary<Type, List<Object>>();

    public static void SerializeDictionary()
        {
            string json = JsonConvert.SerializeObject(_ekstensje);
            System.IO.StreamWriter file = new System.IO.StreamWriter(@"c:\tmp\dictionary.json");
            file.WriteLine(json);

            file.Close();
        }

        public static void DeserializeDictionary()
        {
            string json;
            System.IO.StreamReader file = new System.IO.StreamReader(@"c:\tmp\dictionary.json");
            json = file.ReadToEnd();

            file.Close();
            _ekstensje = JsonConvert.DeserializeObject<Dictionary<Type, List<Object>>>(json);//Deserializacja Dictionary
            Debug.WriteLine(_ekstensje);
        }

        public static List<Object> GetEkstensja(Type className)
        {
            List<Object> list = _ekstensje[className];
            return list;
        }

Exectution:

        ObjectPlus.DeserializeDictionary();
        List<Object> list = ObjectPlus.GetEkstensja(typeof(Remiza));
        foreach (Object o in list)
        {
            Remiza r = (Remiza) o;
            listaRemiz.Add(r);
        }

My problem is when casting to "Remiza" I have that exception:

An exception of type 'System.InvalidCastException' occurred in Osek_MAS_WPF.exe but was not handled in user code. Additional information: Unable to cast object of type 'Newtonsoft.Json.Linq.JObject' to type 'Osek_MAS_WPF.Remiza'.

Thanks for any help!

Zygi
  • 754
  • 8
  • 17
  • If you use a dictionary of object type, the best JSON.net can offer you is Jobject. you're not specifying the type it should try to parse into, so you're not going to be able to get a more specific class out of it. You can write a custom deserializer or put a strong type there. Or leave it as Jobject and parse the entries manually. – William Melani Feb 07 '16 at 16:54
  • Ok, so how can I parse those entries manually from JObject to my type? Thats exactly what I'm trying to achieve. – Zygi Feb 07 '16 at 16:56

2 Answers2

1

This should allow you to convert the JObect to your Remiza type.

ObjectPlus.DeserializeDictionary();
    List<Object> list = ObjectPlus.GetEkstensja(typeof(Remiza));
    foreach (Object o in list)
    {
        Remiza r = o.ToObject<Remiza>();
        listaRemiz.Add(r);
    }

I got this from the stackoverflow answer at the link below. If what I put doesn't work take a look at the link and it should help you to get it running.

https://stackoverflow.com/a/10221594/634769

Community
  • 1
  • 1
divide_byzero
  • 790
  • 2
  • 9
  • 24
  • Unfortunately in my Class Remiza I have list of Persons where Person is abstract class and it's not working because it can't create instance of Person... An exception of type 'Newtonsoft.Json.JsonSerializationException' occurred in Newtonsoft.Json.dll but was not handled in user code Additional information: Could not create an instance of type Osek_MAS_WPF.Osoba. Type is an interface or abstract class and cannot be instantiated. I'm starting to think that serialization isn't the best solution to keep class extension... When there are that kind of associations it's not working as we can see.. – Zygi Feb 07 '16 at 17:25
  • He have to actually cast the object to JObject before using ToObject. Remiza r = ((JObject)o).ToObject(); – mano Feb 07 '16 at 17:34
0

In order to successfully serialize and deserialize polymorphic types with Json.NET, you need to set TypeNameHandling = TypeNameHandling.Auto, like so:

public class ObjectPlus
{
    // Replace with whatever file name is appropriate.  My computer doesn't have a "c:\tmp" directory.
    static string JsonFileName { get { return Path.Combine(Path.GetTempPath(), "dictionary.json"); } }

    static JsonSerializerSettings JsonSettings { get { return new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto, Formatting = Formatting.Indented }; } }

    private static Dictionary<Type, List<Object>> _ekstensje = new Dictionary<Type, List<Object>>();

    public static void SerializeDictionary()
    {
        var path = JsonFileName;

        using (var stream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read))
        using (var writer = new StreamWriter(stream))
        {
            var serializer = JsonSerializer.CreateDefault(JsonSettings);
            serializer.Serialize(writer, _ekstensje);
        }
    }

    public static void DeserializeDictionary()
    {
        var path = JsonFileName;
        try
        {
            using (var stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read))
            using (var reader = new StreamReader(stream))
            using (var jsonReader = new JsonTextReader(reader))
            {
                var serializer = JsonSerializer.CreateDefault(JsonSettings);
                _ekstensje = serializer.Deserialize<Dictionary<Type, List<Object>>>(jsonReader);
            }
        }
        catch (FileNotFoundException)
        {
            // File was not created yet, dictionary should be empty.
            _ekstensje.Clear();
        }
    }

    public static List<Object> GetEkstensja(Type className)
    {
        List<Object> list = _ekstensje[className];
        return list;
    }

    public static void AddEkstensja<T>(T obj)
    {
        List<Object> list;
        if (!_ekstensje.TryGetValue(obj.GetType(), out list))
            list = _ekstensje[obj.GetType()] = new List<object>();
        list.Add(obj);
    }

    internal static string ShowJsonContents()
    {
        if (!File.Exists(JsonFileName))
            return string.Empty;
        return File.ReadAllText(JsonFileName);
    }
}

You should now be able to serialize and deserialize your dictionary when it contains an instance of Remiza.

This will work for types that serialize to objects or collections. However, if your dictionary contains types that serialize to JSON primitives -- for instance an enum or a long -- you may need to encapsulate them in a type wrapper along the lines of Deserialize specific enum into system.enum in Json.Net.

(Incidentally, your _ekstensje dictionary isn't thread-safe.)

dbc
  • 104,963
  • 20
  • 228
  • 340