using System.Collections.Generic;
using Newtonsoft.Json.Linq;
public static void Main()
ParseAndDump("First run", @"{
""field1"": ""my field 1"",
ParseAndDump("Second run", @"{
""field1"": ""new field value""
ParseAndDump("Third run", @"{
private static void ParseAndDump(string comment, string json)
Console.WriteLine("--- " + comment + " ---");
JsonSerializerSettings settings = new JsonSerializerSettings();
settings.Converters.Add(new DtoConverter());
FooDTO foo = JsonConvert.DeserializeObject<FooDTO>(json, settings);
private static void Dump(IHasFieldStatus dto, string indent)
foreach (PropertyInfo prop in dto.GetType().GetProperties())
if (prop.Name == "FieldStatus") continue;
Console.Write(indent + prop.Name + ": ");
object val = prop.GetValue(dto);
if (val is IHasFieldStatus)
Dump((IHasFieldStatus)val, " ");
FieldDeserializationStatus status = dto.FieldStatus[prop.Name];
Console.Write(val.ToString() + " ");
if (status != FieldDeserializationStatus.HasValue)
Console.Write("(" + status + ")");
class DtoConverter : JsonConverter
public override bool CanConvert(Type objectType)
return (objectType.IsClass &&
objectType.GetInterfaces().Any(i => i == typeof(IHasFieldStatus)));
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
var jsonObj = JObject.Load(reader);
var targetObj = (IHasFieldStatus)Activator.CreateInstance(objectType);
var dict = new Dictionary<string, FieldDeserializationStatus>();
targetObj.FieldStatus = dict;
foreach (PropertyInfo prop in objectType.GetProperties())
if (prop.CanWrite && prop.Name != "FieldStatus")
if (jsonObj.TryGetValue(prop.Name, StringComparison.OrdinalIgnoreCase, out value))
if (value.Type == JTokenType.Null)
dict.Add(prop.Name, FieldDeserializationStatus.WasSetToNull);
prop.SetValue(targetObj, value.ToObject(prop.PropertyType, serializer));
dict.Add(prop.Name, FieldDeserializationStatus.HasValue);
dict.Add(prop.Name, FieldDeserializationStatus.WasNotPresent);
public override bool CanWrite
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
throw new NotImplementedException();
enum FieldDeserializationStatus { WasNotPresent, WasSetToNull, HasValue }
interface IHasFieldStatus
Dictionary<string, FieldDeserializationStatus> FieldStatus { get; set; }
class FooDTO : IHasFieldStatus
public string Field1 { get; set; }
public BarDTO Nested { get; set; }
public Dictionary<string, FieldDeserializationStatus> FieldStatus { get; set; }
class BarDTO : IHasFieldStatus
public int Num { get; set; }
public string Str { get; set; }
public bool Bool { get; set; }
public decimal Dec { get; set; }
public Dictionary<string, FieldDeserializationStatus> FieldStatus { get; set; }