using System.Collections.Generic;
using Newtonsoft.Json.Linq;
public static void Main()
""first_name"": ""John"",
""last_name"": ""Smith"",
""vet"": [ ""FOO"", ""VET-1"" ],
""animals"": [ [ ""FOO"", ""ANIMAL-22"" ] ]
""first_name"": ""Susan"",
""last_name"": ""Smith"",
""vet"": [ ""FOO"", ""VET-1"" ]
""vet_name"": ""Acme, Inc"",
""animal_name"": ""Fido"",
""vet"": [ ""FOO"", ""VET-1"" ]
JObject data = JObject.Parse(json);
Dictionary<string, Vet> vets = data["BAR"]
.Where(jp => jp.Value["vet_id"] != null)
.ToDictionary(jp => jp.Name, jp => jp.Value.ToObject<Vet>());
JsonSerializer serializer = new JsonSerializer();
serializer.Converters.Add(new ReferenceConverter<Vet>(vets));
Dictionary<string, Animal> animals = data["BAR"]
.Where(jp => jp.Value["animal_id"] != null)
.ToDictionary(jp => jp.Name, jp => jp.Value.ToObject<Animal>(serializer));
serializer.Converters.Add(new ReferenceConverter<Animal>(animals));
List<User> users = data["users"].ToObject<List<User>>(serializer);
foreach (User user in users)
Console.WriteLine("--------------------");
Console.WriteLine("Name: " + user.FirstName + " " + user.LastName);
Console.WriteLine("Vet: " + (user.Vet != null ? user.Vet.Name : "(none)"));
Console.Write("Animals: ");
if (user.Animals != null && user.Animals.Count > 0)
foreach (Animal a in user.Animals)
Console.WriteLine(" Name: " + a.Name);
Console.WriteLine(" Species: " + a.Species);
Console.WriteLine(" Vet: " + (a.Vet != null ? a.Vet.Name : "(none)"));
Console.WriteLine("(none)");
public class ReferenceConverter<T> : JsonConverter
private Dictionary<string, T> ReferenceDict { get; set; }
public ReferenceConverter(Dictionary<string, T> referenceDict)
ReferenceDict = referenceDict;
public override bool CanConvert(Type objectType)
return objectType == typeof(T);
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
JArray array = JArray.Load(reader);
if (array.Count == 2 && array[0].Type == JTokenType.String && (string)array[0] == "FOO" && array[1].Type == JTokenType.String)
string key = (string)array[1];
if (ReferenceDict.TryGetValue(key, out obj))
throw new JsonSerializationException("No " + typeof(T).Name + " was found with the key \"" + key + "\".");
throw new JsonSerializationException("Reference had an invalid format: " + array.ToString());
public override bool CanWrite
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
throw new NotImplementedException();
[JsonProperty("first_name")]
public string FirstName { get; set; }
[JsonProperty("last_name")]
public string LastName { get; set; }
public Vet Vet { get; set; }
[JsonProperty("animals")]
public List<Animal> Animals { get; set; }
public int Id { get; set; }
[JsonProperty("vet_name")]
public string Name { get; set; }
[JsonProperty("animal_id")]
public int Id { get; set; }
[JsonProperty("animal_name")]
public string Name { get; set; }
public Vet Vet { get; set; }
[JsonProperty("species")]
public string Species { get; set; }