2

I'm grabbing JSON object from an URL and parsing it with JSON.NET. I was able to parse blocks of data with defined variables just fine, but when it comes to random collection of var:value - i'm stuck.

Example(loosely typed):

{"FNAME":"joe","LNAME":"doe",
"BodyType":{"height":180,"weight":"200","race":"white","hair":"black"},
"BELONGINGS":{"shirt":"black","Money":15,"randomThing":"anyvar"},
"Signs":{"tattoo":0,"scar":"forehead","glasses":"dorky"}
}

I'm casting this to

Class Person
{
public string FNAME;
public string LNAME;
public BodyType bodyType;
public ????? belongings;
public ????? signs;
}
How do I handle belongings and signs if i cannot predict their properties?

donkz
  • 313
  • 2
  • 12

2 Answers2

8

There's two ways of handling them without knowing the contents at runtime.

The first way is to use JSON.Net's JObject, which will handle the case you've mentioned, plus hierarchies.

The second way is to use System.Dynamic's ExpandoObject, which is newly supported by recent releases of JSON.Net. Unfortunately it doesn't quite handle hierarchies, but JSON.Net falls back onto JObject to support them when encountered. For your purposes, it might be more straightforward.

Here's an example with the snippet and definitions you've given. Also note that ExpandoObject is directly castable to IDictionary<string, object>, whereas JObject has explicit methods to access properties.

Person corresponds to ExpandoObject, and JPerson corresponds to JObject.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Dynamic;

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

namespace YourFavoriteNamespace
{
    public class JPerson
    {
        public string FNAME;
        public string LNAME;
        public BodyType bodyType;
        public JObject belongings;
        public JObject signs;
    }

    public class Person
    {
        public string FNAME;
        public string LNAME;
        public BodyType bodyType;
        public ExpandoObject belongings;
        public ExpandoObject signs;
    }

    public class BodyType
    {
        public int height;
        public int weight;
        public string race;
        public string hair;
    }

    class Program
    {
        static void DumpDynamic(dynamic d)
        {
            IDictionary<string, object> dynMap = (IDictionary<string, object>)d;
            foreach (string key in dynMap.Keys)
            {
                Console.WriteLine("  {0}={1} (type {2})", key, dynMap[key], null == dynMap[key] ? "null" : dynMap[key].GetType().Name);
            }
        }

        static void DumpJProperties(JObject jo)
        {
            var props = jo.Properties();
            foreach (JProperty prop in props)
            {
                Console.WriteLine("  {0}={1} (type {2})", prop.Name, prop.Value, null == prop.Value ? "null" : prop.Value.GetType().Name);
            }
        }

        static void DumpPerson(Person p)
        {
            Console.WriteLine("Person");
            Console.WriteLine("  FNAME={0}", p.FNAME);
            Console.WriteLine("  LNAME={0}", p.LNAME);
            Console.WriteLine("Person.BodyType");
            Console.WriteLine("  height={0}", p.bodyType.height);
            Console.WriteLine("  weight={0}", p.bodyType.weight);
            Console.WriteLine("  race  ={0}", p.bodyType.race);
            Console.WriteLine("  hair  ={0}", p.bodyType.hair);
            Console.WriteLine("Person.belongings");
            DumpDynamic(p.belongings);
            Console.WriteLine("Person.signs");
            DumpDynamic(p.signs);
        }

        static void DumpJPerson(JPerson p)
        {
            Console.WriteLine("Person");
            Console.WriteLine("  FNAME={0}", p.FNAME);
            Console.WriteLine("  LNAME={0}", p.LNAME);
            Console.WriteLine("Person.BodyType");
            Console.WriteLine("  height={0}", p.bodyType.height);
            Console.WriteLine("  weight={0}", p.bodyType.weight);
            Console.WriteLine("  race  ={0}", p.bodyType.race);
            Console.WriteLine("  hair  ={0}", p.bodyType.hair);
            Console.WriteLine("Person.belongings");
            DumpJProperties(p.belongings);
            Console.WriteLine("Person.signs");
            DumpJProperties(p.signs);
        }

        static void DoSimplePerson()
        {
            string initJson = "{\"FNAME\":\"joe\",\"LNAME\":\"doe\",\"BodyType\":{\"height\":180,\"weight\":\"200\",\"race\":\"white\",\"hair\":\"black\"},\"BELONGINGS\":{\"shirt\":\"black\",\"Money\":15,\"randomThing\":\"anyvar\"},\"Signs\":{\"tattoo\":0,\"scar\":\"forehead\",\"glasses\":\"dorky\"}}";
            Person p = JsonConvert.DeserializeObject<Person>(initJson);
            DumpPerson(p);
            Console.ReadLine();
        }

        static void DoComplexPerson()
        {
            string initJson = "{\"FNAME\":\"joe\",\"LNAME\":\"doe\",\"BodyType\":{\"height\":180,\"weight\":\"200\",\"race\":\"white\",\"hair\":\"black\"},\"BELONGINGS\":{\"shirt\":\"black\",\"Money\":15,\"randomThing\":\"anyvar\"},\"Signs\":{\"tattoo\":0,\"scar\":\"forehead\",\"glasses\":[\"dorky\",\"hipster\"]}}";
            Person p = JsonConvert.DeserializeObject<Person>(initJson);
            DumpPerson(p);
            Console.ReadLine();
        }

        static void DoJPerson()
        {
            string initJson = "{\"FNAME\":\"joe\",\"LNAME\":\"doe\",\"BodyType\":{\"height\":180,\"weight\":\"200\",\"race\":\"white\",\"hair\":\"black\"},\"BELONGINGS\":{\"shirt\":\"black\",\"Money\":15,\"randomThing\":\"anyvar\"},\"Signs\":{\"tattoo\":0,\"scar\":\"forehead\",\"glasses\":\"dorky\"}}";
            JPerson p = JsonConvert.DeserializeObject<JPerson>(initJson);
            DumpJPerson(p);
            Console.ReadLine();
        }

        static void Main(string[] args)
        {
            DoSimplePerson();
            DoComplexPerson();
            DoJPerson();
        }
    }
}
meklarian
  • 6,595
  • 1
  • 23
  • 49
1

Well, they're sure to be JSON objects, right, and JSON objects are associative arrays mapping strings to something. So I'd represent them as Dictionary<string, dynamic> -- a map of strings to somethings.

mqp
  • 70,359
  • 14
  • 95
  • 123