public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { if (contractResolver != serializer.ContractResolver) { throw new InvalidOperationException("Inconsistent contract resolvers"); } Type elementType; JsonProperty keyProperty; if (!CanConvert(contractResolver, objectType, out elementType, out keyProperty)) { throw new JsonSerializationException(string.Format("Invalid input type {0}", objectType)); } if (reader.TokenType == JsonToken.Null) { return(existingValue); } var list = existingValue as IList; if (list == null || list.Count == 0) { list = list ?? (IList)contractResolver.ResolveContract(objectType).DefaultCreator(); serializer.Populate(reader, list); } else { var jArray = JArray.Load(reader); var comparer = new KeyedListMergeComparer(); var lookup = jArray.ToLookup(i => i[keyProperty.PropertyName].ToObject(keyProperty.PropertyType, serializer), comparer); var done = new HashSet <JToken>(); foreach (var item in list) { var key = keyProperty.ValueProvider.GetValue(item); var replacement = lookup[key].Where(v => !done.Contains(v)).FirstOrDefault(); if (replacement != null) { using (var subReader = replacement.CreateReader()) serializer.Populate(subReader, item); done.Add(replacement); } } // Populate the NEW items into the list. if (done.Count < jArray.Count) { foreach (var item in jArray.Where(i => !done.Contains(i))) { list.Add(item.ToObject(elementType, serializer)); } } } return(list); }
object ReadJsonGeneric <T>(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer, JsonProperty keyProperty) { var list = existingValue as IList <T>; if (list == null || list.Count == 0) { list = list ?? (IList <T>)contractResolver.ResolveContract(objectType).DefaultCreator(); serializer.Populate(reader, list); } else { var jArray = JArray.Load(reader); var comparer = new KeyedListMergeComparer(); var lookup = jArray.ToLookup(i => i[keyProperty.PropertyName].ToObject(keyProperty.PropertyType, serializer), comparer); var done = new HashSet <JToken>(); foreach (var item in list) { var key = keyProperty.ValueProvider.GetValue(item); var replacement = lookup[key].Where(v => !done.Contains(v)).FirstOrDefault(); if (replacement != null) { using (var subReader = replacement.CreateReader()) serializer.Populate(subReader, item); done.Add(replacement); } } // Populate the NEW items into the list. if (done.Count < jArray.Count) { foreach (var item in jArray.Where(i => !done.Contains(i))) { list.Add(item.ToObject <T>(serializer)); } } } return(list); }