Пример #1
0
        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);
            }
        }