#define IMPLEMENT_IDICTIONARY
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 MyContractResolver : DefaultContractResolver
protected override JsonContract CreateContract(Type objectType)
if (typeof(MyDynamicObject).IsAssignableFrom(objectType))
return CreateDynamicContract(objectType);
return base.CreateContract(objectType);
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
var properties = base.CreateProperties(type, memberSerialization);
if (type.IsSubclassOf(typeof(MyDynamicObject)) && memberSerialization == MemberSerialization.OptOut)
foreach (var property in properties)
if (!property.Ignored && property.DeclaringType.IsSubclassOf(typeof(MyDynamicObject)))
property.HasMemberAttribute = true;
public class MyDynamicObject : DynamicObject
#if IMPLEMENT_IDICTIONARY
, IDictionary<string, object>
private Dictionary<string, object> m_Members;
this.m_Members = new Dictionary<string, object>();
#if IMPLEMENT_IDICTIONARY
public int Count { get { return this.m_Members.Count; } }
public ICollection<string> Keys { get { return this.m_Members.Keys; } }
public ICollection<object> Values { get { return this.m_Members.Values; } }
bool ICollection<KeyValuePair<string, object>>.IsReadOnly { get { return false; } }
public object this[string memberName]
if (this.m_Members.TryGetValue(memberName, out value))
set { this.m_Members[memberName] = value; }
public override bool TryGetMember(GetMemberBinder binder, out object result)
this.m_Members.TryGetValue(binder.Name, out result);
public override bool TrySetMember(SetMemberBinder binder, object value)
this.m_Members[binder.Name] = value;
public override bool TryDeleteMember(DeleteMemberBinder binder)
return this.m_Members.Remove(binder.Name);
public override IEnumerable<string> GetDynamicMemberNames()
var names = base.GetDynamicMemberNames();
return this.m_Members.Keys;
#if IMPLEMENT_IDICTIONARY
bool IDictionary<string, object>.ContainsKey(string memberName)
return this.m_Members.ContainsKey(memberName);
public void Add(string memberName, object value)
this.m_Members.Add(memberName, value);
public bool Remove(string memberName)
return this.m_Members.Remove(memberName);
public bool TryGetValue(string memberName, out object value)
return this.m_Members.TryGetValue(memberName, out value);
void ICollection<KeyValuePair<string, object>>.Add(KeyValuePair<string, object> member)
((IDictionary<string, object>)this.m_Members).Add(member);
bool ICollection<KeyValuePair<string, object>>.Contains(KeyValuePair<string, object> member)
return ((IDictionary<string, object>)this.m_Members).Contains(member);
public void CopyTo(KeyValuePair<string, object>[] array, int arrayIndex)
((IDictionary<string, object>)this.m_Members).CopyTo(array, arrayIndex);
bool ICollection<KeyValuePair<string, object>>.Remove(KeyValuePair<string, object> member)
return ((IDictionary<string, object>)this.m_Members).Remove(member);
public IEnumerator<KeyValuePair<string, object>> GetEnumerator()
return this.m_Members.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator()
return this.m_Members.GetEnumerator();
public class CustomDynamicObject : MyDynamicObject
public string Name { get; set; }
public ProxyInfo Proxy { get; set; }
public string Ignore { get; set; }
static IContractResolver resolver = new MyContractResolver();
public static void Test()
var contract = resolver.ResolveContract(typeof(CustomDynamicObject));
Console.WriteLine("Contract for {0}: {1}", typeof(CustomDynamicObject), contract);
Console.WriteLine(string.Join("\n", ((JsonDynamicContract)contract).Properties.Select(p => string.Format(" {0}: Ignored={1}", p, p.Ignored))));
dynamic obj = new CustomDynamicObject()
Proxy = new ProxyInfo() { Server = "http://test.com/", Port = 10102 }
var settings = new JsonSerializerSettings
ContractResolver = resolver,
string json = JsonConvert.SerializeObject(obj, settings);
string expectedJson = "{ \"Prop1\":\"P1\", \"Prop2\":320, \"Name\":\"Test1\", \"Proxy\":{ \"Server\":\"http://test.com/\", \"Port\":10102 } }";
Assert.IsTrue(JToken.DeepEquals(JToken.Parse(expectedJson), JToken.Parse(json)));
CustomDynamicObject deserializedObj = JsonConvert.DeserializeObject<CustomDynamicObject>(expectedJson, settings);
Assert.IsTrue(deserializedObj.Name == obj.Name);
Assert.IsTrue(obj.Count == deserializedObj.Count);
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: ");