-1

In PHP and Python I can deserialise a JSON document to a dictionary structure. That's the default behaviour and there are not many other options anyway. In C#, hovever, all is typed and System.Text.Json methods want to know what type to deserialise into. Since I don't know the structure of the JSON document and just need to pass it on to something that can handle a dictionary, I need to convert it to that.

This doesn't work as expected:

var dict = System.Text.Json.JsonSerializer.Deserialize<Dictionary<string, object>>("{ \"a\": 1, \"b\": { \"c\": 3 } }");

At least what the VSCode debugger shows me, I have a dictionary with the keys "a" and "b" but the values are anything. I'd expect to see an int as value for "a" and another Dictionary as value for "b" with an int for the value "c".

How can this be achieved?

I'm looking for something like this:

// Does not exist:
var dict = System.Text.Json.JsonSerializer.DeserializeToDictionary("{ \"a\": 1, \"b\": { \"c\": 3 } }");

I'm trying to convert a class that I've written in Python because I hit other roadblocks in Python. I'm more experienced in C# so I'd like to solve the problem there, but JSON for dynamic data isn't a strength of C#. Seems I have to write some classes of my application in Python and others in C# to get it done.

ygoe
  • 18,655
  • 23
  • 113
  • 210
  • 3
    C# isn't PHP and even in Python you *have* types, even when you don't explicitly specify them. Why is a `Dictionary` used at all? That's where the problem starts, not in `Deserialize<>`. You could use a generic method that allows specifying the type later on. For arbitrary parsing, a `JsonDocument` would be better. You could deserialize to `dynamic` but that would lose all compile-time type checking. A `Dictionary` is the worst possible type because there's no way to use the values without reflection – Panagiotis Kanavos Dec 21 '22 at 12:26
  • 1
    If you *really really* need dictionaries (*why???*), JSON.NET would be a better option. [JObject](https://www.newtonsoft.com/json/help/html/t_newtonsoft_json_linq_jobject.htm) implements `IDictionary`. – Panagiotis Kanavos Dec 21 '22 at 12:29
  • In the absence of a converter or polymorphic type information System.Text.Json will deserialize anything declared as an `object` to a `JsonElement` or `JsonNode`, depending upon the setting for [`UnknownTypeHandling`](https://docs.microsoft.com/en-us/dotnet/api/system.text.json.jsonserializeroptions.unknowntypehandling). Thus your `Dictionary` gets populated with `JsonElement` values. – dbc Dec 21 '22 at 17:51
  • If you would prefer to deserialize to a hierarchy of dictionaries, lists and .NET Primitives, you could use `ObjectAsPrimitiveConverter` from [this answer](https://stackoverflow.com/a/65974452/3744182) to [C# - Deserializing nested json to nested Dictionary](https://stackoverflow.com/q/65972825/3744182). In fact I think that's a duplicate, agree? – dbc Dec 21 '22 at 17:51

1 Answers1

1

Newtonsoft.Json fits much better for the complicated cases. You can try this code

   using Newtonsoft.Json;

    var jsonParsed = JObject.Parse(json);
    var dict = new Dictionary<string, object>();
    
    AddDictionaries(dict,jsonParsed);

public void AddDictionaries(Dictionary<string, object> dict, JObject jsonObj)
{
    foreach (var prop in jsonObj)
    {
        if (prop.Value.Type != JTokenType.Object)
            dict.Add(prop.Key, prop.Value);
        else
        {
            var nestedDict = new Dictionary<string, object>();
            AddDictionaries(nestedDict, (JObject)prop.Value);
            dict.Add(prop.Key, nestedDict);
        }
    }
}
Serge
  • 40,935
  • 4
  • 18
  • 45