You have a few alternatives to force your list to be replaced rather than reused:
-
You can add an attribute to the list property indicating that it should be replaced not reused:
public class Configuration { [JsonProperty(ObjectCreationHandling = ObjectCreationHandling.Replace)] public List<Tuple<int, int, int>> MyThreeTuple { get; set; } }
-
You can use an array instead of a list, as arrays are always replaced. This might make sense if your list should always contain three items and is never resized:
public class Configuration { public Tuple<int, int, int>[] MyThreeTuple { get; set; } public Configuration() { MyThreeTuple = new[] { new Tuple<int, int, int>(-100, 20, 501), new Tuple<int, int, int>(100, 20, 864), new Tuple<int, int, int>(500, 20, 1286), }; } }
-
If you don’t want your class definitions to have a dependency on Json.NET, you can make a custom
JsonConverter
that clears the list when deserializing:public class ConfigurationConverter : JsonConverter { public override bool CanConvert(Type objectType) { return typeof(Configuration).IsAssignableFrom(objectType); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { var config = (existingValue as Configuration ?? (Configuration)serializer.ContractResolver.ResolveContract(objectType).DefaultCreator()); if (config.MyThreeTuple != null) config.MyThreeTuple.Clear(); serializer.Populate(reader, config); return config; } public override bool CanWrite { get { return false; } } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { throw new NotImplementedException(); } }
Then use it with the following
JsonSerializerSettings
:var settings = new JsonSerializerSettings { Converters = new JsonConverter[] { new ConfigurationConverter() } };
-
If you want all list properties to be replaced rather than reused, you can make a custom
ContractResolver
that does this:public class ListReplacementContractResolver : DefaultContractResolver { // As of 7.0.1, Json.NET suggests using a static instance for "stateless" contract resolvers, for performance reasons. // http://www.newtonsoft.com/json/help/html/ContractResolver.htm // http://www.newtonsoft.com/json/help/html/M_Newtonsoft_Json_Serialization_DefaultContractResolver__ctor_1.htm // "Use the parameterless constructor and cache instances of the contract resolver within your application for optimal performance." static readonly ListReplacementContractResolver instance; // Using a static constructor enables fairly lazy initialization. http://csharpindepth.com/Articles/General/Singleton.aspx static ListReplacementContractResolver() { instance = new ListReplacementContractResolver(); } public static ListReplacementContractResolver Instance { get { return instance; } } protected ListReplacementContractResolver() : base() { } protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) { var jsonProperty = base.CreateProperty(member, memberSerialization); if (jsonProperty.ObjectCreationHandling == null && jsonProperty.PropertyType.GetListType() != null) jsonProperty.ObjectCreationHandling = ObjectCreationHandling.Replace; return jsonProperty; } } public static class TypeExtensions { public static Type GetListType(this Type type) { while (type != null) { if (type.IsGenericType) { var genType = type.GetGenericTypeDefinition(); if (genType == typeof(List<>)) return type.GetGenericArguments()[0]; } type = type.BaseType; } return null; } }
Then use it with the following settings:
var settings = new JsonSerializerSettings { ContractResolver = ListReplacementContractResolver.Instance };
-
If the collection is get-only (which it is not in this case) see Clear collections before adding items when populating existing objects.