facebook-csharp-sdk/simple-json

Deserialize anonymous types

Opened this issue · 0 comments

I've written a serializer strategy that supports deserializing anonymous types and thought I'd share the code here for anyone who's interested. Anonymous types are immutable, with all property values passed in via constructor parameters. The strategy detects the absence of a default (parameterless) public constructor and builds the necessary cached ConstructorDelegate to create and populate the output object.

public static class SimpleJsonExt
{
    public static T DeserializeAnonymousObject<T>(string json, T prototype)
    {
        return SimpleJson.SimpleJson.DeserializeObject<T>(json, new Strategy());
    }

    private class Strategy : PocoJsonSerializerStrategy
    {
        private readonly IDictionary<Type, KeyValuePair<ParameterInfo[], ReflectionUtils.ConstructorDelegate>> _ctorCache = new ReflectionUtils.ThreadSafeDictionary<Type, KeyValuePair<ParameterInfo[], ReflectionUtils.ConstructorDelegate>>(CreateConstructorDelegate);

        private static KeyValuePair<ParameterInfo[], ReflectionUtils.ConstructorDelegate> CreateConstructorDelegate(Type key)
        {
            var ctors = key.GetConstructors();
            if (ctors.Length == 1)
            {
                var ctor = ctors[0];
                var parms = ctor.GetParameters();
                if (parms.Length > 0)
                {
                    return new KeyValuePair<ParameterInfo[], ReflectionUtils.ConstructorDelegate>(parms, ReflectionUtils.GetConstructor(ctor));
                }
            }
            return default(KeyValuePair<ParameterInfo[], ReflectionUtils.ConstructorDelegate>);
        }

        public override object DeserializeObject(object value, Type type)
        {
            var dict = value as IDictionary<string, object>;
            if (dict != null)
            {
                var ctor = _ctorCache[type];
                if (ctor.Key != null)
                {
                    object arg;
                    return ctor.Value(ctor.Key.Select(param => DeserializeObject(dict.TryGetValue(param.Name, out arg) ? arg : null, param.ParameterType)).ToArray());
                }
            }
            return base.DeserializeObject(value, type);
        }
    }
}