using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Collections.ObjectModel;
using System.Runtime.Serialization;
using System.ComponentModel;
using System.Globalization;
using System.Collections.Specialized;
using System.Text.RegularExpressions;
using System.Runtime.Serialization.Formatters;
using System.Linq.Expressions;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;
public class IncludeMethodsContractResolver : DefaultContractResolver
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
var properties = base.CreateProperties(type, memberSerialization);
return properties.Concat(this.GetMethodProperties(type, memberSerialization)).ToList();
internal static class ContractResolverExtensions
static readonly HashSet<string> objectMethods;
static ContractResolverExtensions()
objectMethods = new HashSet<string>(typeof(object).GetMethods().Where(m => IsCallableMethod(m)).Select(m => m.Name));
static Func<object, object> CreateMethodGetterGeneric<TObject, TValue>(MethodInfo method)
throw new ArgumentNullException();
var func = (Func<TObject, TValue>)Delegate.CreateDelegate(typeof(Func<TObject, TValue>), method);
return (o) => func((TObject)o);
static Func<object, object> CreateMethodGetter(MethodInfo method, Type type)
var myMethod = typeof(ContractResolverExtensions).GetMethod("CreateMethodGetterGeneric", BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Public);
return (Func<object, object>)myMethod.MakeGenericMethod(new[] { type, method.ReturnType }).Invoke(null, new [] { method });
static bool IsCallableMethod(MethodInfo m)
return !m.ContainsGenericParameters && m.GetParameters().Length == 0 && !m.IsAbstract && m.ReturnType != typeof(void) && !m.IsSpecialName;
public static IEnumerable<JsonProperty> GetMethodProperties(this DefaultContractResolver resolver, Type type, MemberSerialization memberSerialization)
if (type.IsValueType || memberSerialization == MemberSerialization.Fields || memberSerialization == MemberSerialization.OptIn)
return Enumerable.Empty<JsonProperty>();
var query = from m in type.GetMethods()
where IsCallableMethod(m)
where !objectMethods.Contains(m.Name)
let v = new MethodProvider(CreateMethodGetter(m, type))
PropertyType = m.ReturnType,
PropertyName = resolver.GetResolvedPropertyName(m.Name),
AttributeProvider = NoAttributeProvider.Instance,
class NoAttributeProvider : IAttributeProvider
static NoAttributeProvider() { instance = new NoAttributeProvider(); }
static readonly NoAttributeProvider instance;
public static NoAttributeProvider Instance { get { return instance; } }
public IList<Attribute> GetAttributes(Type attributeType, bool inherit) { return new Attribute[0]; }
public IList<Attribute> GetAttributes(bool inherit) { return new Attribute[0]; }
class MethodProvider : IValueProvider
readonly Func<object, object> methodGetter;
public MethodProvider(Func<object, object> methodGetter)
if (methodGetter == null)
throw new ArgumentNullException();
this.methodGetter = methodGetter;
#region IValueProvider Members
public object GetValue(object target)
return methodGetter(target);
public void SetValue(object target, object value)
throw new NotImplementedException();
public string InnerValue { get; set; }
public override string ToString()
public class Property3<T>
internal T ValueX { get; set; }
public string SubPropertyA { get; set; }
public T SomeMethodX() { return ValueX; }
public TSomething ShouldNotBeSerialized1<TSomething>() { return default(TSomething); }
public int ShouldNotBeSerialized2(int argument) { return argument; }
public void ShouldNotBeSerialized3() { }
public class RootObject<T>
public string Property1 { get; set; }
public string Property2 { get; set; }
public Property3<T> Property3 { get; set; }
public static void Test()
var root = new RootObject<InnerClass>
Property1 = "valueOfProperty1",
Property2 = "valueOfProperty2",
Property3 = new Property3<InnerClass>
InnerValue = "inner class value",
SubPropertyA = "valueOfSubPropertyA",
Console.WriteLine("\nDefault serialization of {0}:", root);
var defaultJson = JsonConvert.SerializeObject(root, Formatting.Indented);
Console.WriteLine(defaultJson);
var settings = new JsonSerializerSettings
ContractResolver = new IncludeMethodsContractResolver(),
var customJson = JsonConvert.SerializeObject(root, Formatting.Indented, settings);
Console.WriteLine("\nCustom serialization of {0} with methods included:", root);
Console.WriteLine(customJson);
Assert.IsTrue(!customJson.Contains("ShouldNotBeSerialized"));
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");