using System.Collections;
using System.Collections.Generic;
using System.Runtime.Serialization.Formatters;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.ComponentModel;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;
[DefaultValue(new int[] { 4, 6, 12 })]
public class ArrayDefaultValueContractResolver : DefaultContractResolver
class ArrayDefaultValueProvider : IValueProvider
readonly IValueProvider baseProvider;
readonly System.Array defaultValue;
public ArrayDefaultValueProvider(IValueProvider baseProvider, System.Array defaultValue)
this.baseProvider = baseProvider;
this.defaultValue = defaultValue;
#region IValueProvider Members
public object GetValue(object target)
return baseProvider.GetValue(target);
public void SetValue(object target, object value)
if (value != null && object.ReferenceEquals(value, defaultValue))
value = defaultValue.Clone();
baseProvider.SetValue(target, value);
static void AddArrayDefaultHandling<T>(JsonProperty property)
var defaultValue = (T [])property.DefaultValue;
if (defaultValue.Length > 0)
property.ValueProvider = new ArrayDefaultValueProvider(property.ValueProvider, defaultValue);
var valueProvider = property.ValueProvider;
var oldShouldSerialize = property.ShouldSerialize;
Predicate<object> shouldSerialize = target =>
var array = (T[])valueProvider.GetValue(target);
return !(array == null || array.SequenceEqual(defaultValue));
if (oldShouldSerialize == null)
property.ShouldSerialize = shouldSerialize;
property.ShouldSerialize = (target) => shouldSerialize(target) && oldShouldSerialize(target);
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
var property = base.CreateProperty(member, memberSerialization);
if (property.PropertyType.IsArray && property.DefaultValue != null && property.DefaultValue.GetType() == property.PropertyType
&& property.PropertyType.GetArrayRank() == 1)
typeof(ArrayDefaultValueContractResolver)
.GetMethod("AddArrayDefaultHandling", BindingFlags.Static | BindingFlags.NonPublic)
.MakeGenericMethod(property.PropertyType.GetElementType())
.Invoke(null, BindingFlags.Static | BindingFlags.NonPublic, null, new [] { property }, null);
public static void Test()
Console.WriteLine("\nTesting complex fix using {0}", typeof(ArrayDefaultValueContractResolver));
static IContractResolver resolver = new ArrayDefaultValueContractResolver();
public static void TestOriginal()
var serializerSettings = new JsonSerializerSettings
ContractResolver = resolver,
DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate,
JsonConvert.PopulateObject("{}", a, serializerSettings);
Console.WriteLine(JsonConvert.SerializeObject(a, serializerSettings));
Assert.IsTrue(JsonConvert.SerializeObject(a, serializerSettings) == "{}");
a.SomeArray = new int[] { 4, 6, 12 };
Console.WriteLine(JsonConvert.SerializeObject(a, serializerSettings));
Assert.IsTrue(JsonConvert.SerializeObject(a, serializerSettings) == "{}");
var serializerSettings = new JsonSerializerSettings
DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate,
ContractResolver = resolver,
var a1 = JsonConvert.DeserializeObject<A>("{}", serializerSettings);
Assert.IsTrue(a1.SomeArray.SequenceEqual(new int[] { 4, 6, 12 }));
var a2 = JsonConvert.DeserializeObject<A>("{}", serializerSettings);
Assert.IsTrue(a2.SomeArray.SequenceEqual(new int[] { 4, 6, 12 }));
public static void Main()
Console.WriteLine("Environment version: " + Environment.Version);
Console.WriteLine("Json.NET version: " + typeof(JsonSerializer).Assembly.FullName);
Console.WriteLine("Failed with unhandled exception: ");