using System.Collections;
using System.Collections.Generic;
using System.Runtime.Serialization.Formatters;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;
public class ConvertibleDictionaryConverter : JsonConverter
[JsonDictionary(ItemTypeNameHandling = TypeNameHandling.Auto)]
class ConvertibleDictionaryDTO : Dictionary<string, ConvertibleWrapper>
public ConvertibleDictionaryDTO() : base() { }
public ConvertibleDictionaryDTO(int count) : base(count) { }
public override bool CanConvert(Type objectType)
return typeof(IDictionary<string, IConvertible>).IsAssignableFrom(objectType);
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
var dto = serializer.Deserialize<ConvertibleDictionaryDTO>(reader);
var dictionary = (IDictionary<string, IConvertible>)(existingValue ?? serializer.ContractResolver.ResolveContract(objectType).DefaultCreator());
foreach (var pair in dto)
dictionary.Add(pair.Key, pair.Value.ObjectValue);
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
var dictionary = (IDictionary<string, IConvertible>)value;
var dto = new ConvertibleDictionaryDTO(dictionary.Count);
foreach (var pair in dictionary)
dto.Add(pair.Key, ConvertibleWrapper.CreateWrapper(pair.Value));
serializer.Serialize(writer, dto);
abstract class ConvertibleWrapper
protected ConvertibleWrapper() { }
public abstract IConvertible ObjectValue { get; }
public static ConvertibleWrapper CreateWrapper<T>(T value) where T : IConvertible
return new ConvertibleWrapper<T>();
var type = value.GetType();
return new ConvertibleWrapper<T>(value);
return (ConvertibleWrapper)Activator.CreateInstance(typeof(ConvertibleWrapper<>).MakeGenericType(type), value);
sealed class ConvertibleWrapper<T> : ConvertibleWrapper where T : IConvertible
public ConvertibleWrapper() : base() { }
public ConvertibleWrapper(T value)
public override IConvertible ObjectValue { get { return Value; } }
public T Value { get; set; }
public static void Test()
var dic = new Dictionary<string, IConvertible>();
dic.Add("string2", "hellohello");
dic.Add("null value", null);
var settings = new JsonSerializerSettings
Converters = { new ConvertibleDictionaryConverter() },
TypeNameAssemblyFormat = FormatterAssemblyStyle.Full,
var dicString = JsonConvert.SerializeObject(dic, Newtonsoft.Json.Formatting.Indented, settings);
Console.WriteLine(dicString);
var dic2 = JsonConvert.DeserializeObject<Dictionary<string, IConvertible>>(dicString, settings);
var result = object.ReferenceEquals(dic, dic2)
|| (dic.Count == dic2.Count && !dic.Except(dic2).Any());
Assert.IsTrue(result, "Dictionaries are NOT identical.");
Console.WriteLine("Deserialized dictionary is identical to original.");
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: ");
public class AssertionFailedException : System.Exception
public AssertionFailedException() : base() { }
public AssertionFailedException(string s) : base(s) { }
public static class Assert
public static void IsTrue(bool value)
public static void IsTrue(bool value, string message)
throw new AssertionFailedException(message ?? "failed");