using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Runtime.Serialization;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;
namespace Question42165648
public class CollectionClearingContractResolver : DefaultContractResolver
static void ClearGenericCollectionCallback<T>(object o, StreamingContext c)
var collection = o as ICollection<T>;
if (collection == null || collection is Array || collection.IsReadOnly)
static SerializationCallback ClearListCallback = (o, c) =>
var collection = o as IList;
if (collection == null || collection is Array || collection.IsReadOnly)
protected override JsonArrayContract CreateArrayContract(Type objectType)
var contract = base.CreateArrayContract(objectType);
if (typeof(IList).IsAssignableFrom(objectType))
contract.OnDeserializingCallbacks.Add(ClearListCallback);
else if (objectType.GetCollectItemTypes().Count() == 1)
MethodInfo method = typeof(CollectionClearingContractResolver).GetMethod("ClearGenericCollectionCallback", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
MethodInfo generic = method.MakeGenericMethod(contract.CollectionItemType);
contract.OnDeserializingCallbacks.Add((SerializationCallback)Delegate.CreateDelegate(typeof(SerializationCallback), generic));
public static class TypeExtensions
public static IEnumerable<Type> GetInterfacesAndSelf(this Type type)
throw new ArgumentNullException();
return new[] { type }.Concat(type.GetInterfaces());
return type.GetInterfaces();
public static IEnumerable<Type> GetCollectItemTypes(this Type type)
foreach (Type intType in type.GetInterfacesAndSelf())
if (intType.IsGenericType
&& intType.GetGenericTypeDefinition() == typeof(ICollection<>))
yield return intType.GetGenericArguments()[0];
public static class JsonExtensions
public static void Populate<T>(this JToken value, T target) where T : class
value.Populate(target, null);
public static void Populate<T>(this JToken value, T target, JsonSerializerSettings settings) where T : class
using (var sr = value.CreateReader())
JsonSerializer.CreateDefault(settings).Populate(sr, target);
readonly HashSet<int> hashSet = new HashSet<int>();
public string Value { get; set; }
public NestedObject NestedObject { get; set; }
public int[] ArrayValues { get; set; }
public List<int> ListValues { get; set; }
public HashSet<int> HashSetValues { get { return this.hashSet; } }
public class NestedObject
public string NestedValue { get; set; }
static JObject GetJsonToPopulate()
return JObject.Parse(json);
static JObject GetExpectedJsonAfterPopulate()
""Value"": ""this should not get replaced"",
""NestedValue"": ""this should not get replaced""
return JObject.Parse(json);
internal static void Test()
var root = new RootObject
Value = "this should not get replaced",
NestedObject = new NestedObject { NestedValue = "this should not get replaced" },
ArrayValues = new[] { 1, 2 },
ListValues = new List<int> { 1, 2 },
HashSetValues = { 1, 2 },
Test(root, new JObject(), JObject.FromObject(root));
Test(root, GetJsonToPopulate(), GetExpectedJsonAfterPopulate());
private static void Test(RootObject root, JObject toPopulate, JObject expected)
var settings = new JsonSerializerSettings
ContractResolver = new CollectionClearingContractResolver(),
var json = JsonConvert.SerializeObject(root, Formatting.Indented, settings);
Console.WriteLine("Initial object JSON: ");
Console.WriteLine("Json to populate onto object: ");
Console.WriteLine(toPopulate);
toPopulate.Populate(root, settings);
var json2 = JsonConvert.SerializeObject(root, Formatting.Indented, settings);
Console.WriteLine("Result of populating object: ");
Console.WriteLine(json2);
Assert.IsTrue(JToken.DeepEquals(expected, JToken.Parse(json2)));
Console.WriteLine("Populated JSON is as expected.");
public static class Assert
public static void IsTrue(bool value)
throw new AssertionFailedException("failed");
public class AssertionFailedException : System.Exception
public AssertionFailedException() : base() { }
public AssertionFailedException(string s) : base(s) { }
public static void Main()
Console.WriteLine("Json.NET version: " + typeof(JsonSerializer).Assembly.FullName);
Question42165648.TestClass.Test();