static object ReadValue(Type inst_type, JsonData json) { if (json == null || json.JsonType == JsonType.None || (json.JsonType == JsonType.String && String.IsNullOrEmpty((string)json.Value) && !(inst_type == typeof(string)))) { if (inst_type.IsGenericType && inst_type.GetGenericTypeDefinition() == typeof(Nullable <>)) { return(Activator.CreateInstance(inst_type)); // empty nullable } if (!inst_type.IsClass && !inst_type.IsArray) { throw new JsonException(String.Format("Can't assign null to an instance of type {0}", inst_type)); } return(null); } object[] attrs; if ((attrs = inst_type.GetCustomAttributes(typeof(JsonConverterAttribute), false)) != null && attrs.Length == 1) { var jca = (JsonConverterAttribute)attrs[0]; var jc = (IJsonConverter)Activator.CreateInstance(jca.Converter); object v_; if (jc.Deserialize(json, inst_type, out v_)) { return(v_); } } if (inst_type.IsGenericType && inst_type.GetGenericTypeDefinition() == typeof(Nullable <>)) // 'json' isn't null -> has a value { return(Activator.CreateInstance(inst_type, ReadValue(inst_type.GetGenericArguments()[0], json))); } var v = json.Value; switch (json.JsonType) { case JsonType.Double: case JsonType.Int: case JsonType.Long: case JsonType.String: case JsonType.Boolean: return(ConvertTo(inst_type, json.Value, json.NetType(inst_type))); case JsonType.Array: { AddArrayMetadata(inst_type); ArrayMetadata t_data = array_metadata[inst_type]; if (!t_data.IsArray && !t_data.IsList) { throw new JsonException(String.Format("Type {0} can't act as an array", inst_type)); } var inList = (IList <JsonData>)v; IList list; Type elem_type; if (!t_data.IsArray) { list = (IList)Activator.CreateInstance(inst_type); elem_type = t_data.ElementType; } else { list = new List <object>(); elem_type = inst_type.GetElementType(); } for (int i = 0; i < inList.Count; i++) { list.Add(ReadValue(elem_type, inList[i])); } object inst; if (t_data.IsArray) { int n = list.Count; inst = Array.CreateInstance(elem_type, n); for (int i = 0; i < n; i++) { ((Array)inst).SetValue(list[i], i); } } else { inst = list; } return(inst); } case JsonType.Object: { AddObjectMetadata(inst_type); ObjectMetadata t_data = object_metadata[inst_type]; //throw new Exception("type is " + inst_type); var inst = Activator.CreateInstance(inst_type); var dict = (IDictionary <string, JsonData>)v; foreach (var kvp in dict) { var prop = kvp.Key; var value = kvp.Value; PropertyMetadata prop_data; if (TryGetValueIgnCase(t_data.Properties, prop, out prop_data)) { if (prop_data.IsField) { ((FieldInfo)prop_data.Info).SetValue(inst, ReadValue(prop_data.Type, value)); } else { var p_info = (PropertyInfo)prop_data.Info; var v_ = ReadValue(prop_data.Type, value); object converted = null; if ((attrs = p_info.GetCustomAttributes(typeof(JsonConverterAttribute), false)) != null && attrs.Length == 1) { var jca = (JsonConverterAttribute)attrs[0]; var jc = (IJsonConverter)Activator.CreateInstance(jca.Converter); jc.Deserialize(value, p_info.PropertyType, out converted); } if (p_info.CanWrite) { p_info.SetValue(inst, converted ?? ConvertTo(p_info.PropertyType, v_), null); } else { throw new MemberAccessException("Cannot set property '" + p_info + "' to '" + v_ + "'."); } } } else { if (!t_data.IsDictionary) { throw new JsonException(String.Format("The type {0} doesn't have the property '{1}'", inst_type, prop)); } ((IDictionary)inst).Add(prop, ReadValue(t_data.ElementType, value)); } } return(inst); } default: return(null); } }