Ejemplo n.º 1
0
        private static object ReadValue(Type instType, JsonReader reader)
        {
            reader.Read();
            if (reader.Token == JsonToken.ArrayEnd)
            {
                return(null);
            }
            Type underlyingType = Nullable.GetUnderlyingType(instType);
            Type valueType      = underlyingType ?? instType;

            if (reader.Token == JsonToken.Null)
            {
                        #if JSON_WINRT || (UNITY_METRO && !UNITY_EDITOR)
                /* IsClass is made a getter here as a comparability
                 * patch for WinRT build targets, see Platform.cs */
                if (instType.IsClass() || underlyingType != null)
                {
                        #else
                if (instType.IsClass || underlyingType != null)
                {
                        #endif
                    return(null);
                }
                throw new JsonException(string.Format("Can't assign null to an instance of type {0}", instType));
            }
            if (reader.Token == JsonToken.Real ||
                reader.Token == JsonToken.Natural ||
                reader.Token == JsonToken.String ||
                reader.Token == JsonToken.Boolean)
            {
                Type jsonType = reader.Value.GetType();
                if (valueType.IsAssignableFrom(jsonType))
                {
                    return(reader.Value);
                }
                // Try to find a custom or base importer
                ImporterFunc importer = GetImporter(jsonType, valueType);
                if (importer != null)
                {
                    return(importer(reader.Value));
                }
                // Maybe it's an enum
                        #if JSON_WINRT || (UNITY_METRO && !UNITY_EDITOR)
                /* IsClass is made a getter here as a comparability
                 * patch for WinRT build targets, see Platform.cs */
                if (valueType.IsEnum())
                {
                        #else
                if (valueType.IsEnum)
                {
                        #endif
                    return(Enum.ToObject(valueType, reader.Value));
                }
                // Try using an implicit conversion operator
                MethodInfo convOp = GetConvOp(valueType, jsonType);
                if (convOp != null)
                {
                    return(convOp.Invoke(null, new object[] { reader.Value }));
                }
                // No luck
                throw new JsonException(string.Format("Can't assign value '{0}' (type {1}) to type {2}", reader.Value, jsonType, instType));
            }
            object instance = null;
            if (reader.Token == JsonToken.ArrayStart)
            {
                // If there's a custom importer that fits, use it
                ImporterFunc importer = GetImporter(typeof(JsonData), instType);
                if (importer != null)
                {
                    instType = typeof(JsonData);
                }
                AddArrayMetadata(instType);
                ArrayMetadata tdata = arrayMetadata[instType];
                if (!tdata.IsArray && !tdata.IsList)
                {
                    throw new JsonException(string.Format("Type {0} can't act as an array", instType));
                }
                IList list;
                Type  elemType;
                if (!tdata.IsArray)
                {
                    list     = (IList)CreateInstance(instType);
                    elemType = tdata.ElementType;
                }
                else
                {
                    //list = new ArrayList();
                    list     = new List <object>();
                    elemType = instType.GetElementType();
                }
                while (true)
                {
                    object item = ReadValue(elemType, reader);
                    if (item == null && reader.Token == JsonToken.ArrayEnd)
                    {
                        break;
                    }
                    list.Add(item);
                }
                if (tdata.IsArray)
                {
                    int n = list.Count;
                    instance = Array.CreateInstance(elemType, n);
                    for (int i = 0; i < n; i++)
                    {
                        ((Array)instance).SetValue(list[i], i);
                    }
                }
                else
                {
                    instance = list;
                }
                if (importer != null)
                {
                    instance = importer(instance);
                }
            }
            else if (reader.Token == JsonToken.ObjectStart)
            {
                bool   done     = false;
                string property = null;
                reader.Read();
                if (reader.Token == JsonToken.ObjectEnd)
                {
                    done = true;
                }
                else
                {
                    property = (string)reader.Value;
                    if (reader.TypeHinting && property == reader.HintTypeName)
                    {
                        valueType = reader.ReadType();
                        reader.Read();
                        property = (string)reader.Value;
                        //reader.Read();
                        //string typeName = (string)reader.Value;
                        //reader.Read();
                        //if ((string)reader.Value == reader.HintValueName)
                        //{
                        //    valueType = Type.GetType(typeName);
                        //    object value = ReadValue(valueType, reader);
                        //    reader.Read();
                        //    if (reader.Token != JsonToken.ObjectEnd)
                        //    {
                        //        throw new JsonException(string.Format("Invalid type hinting object, has too many properties: {0}...", reader.Token));
                        //    }
                        //    return value;
                        //}
                        //else
                        //{
                        //    throw new JsonException(string.Format("Expected \"{0}\" property for type hinting but instead got \"{1}\"", reader.HintValueName, reader.Value));
                        //}
                    }
                }
                // If there's a custom importer that fits, use to create a JsonData type instead.
                // Once the object is deserialzied, it will be invoked to create the actual converted object.
                ImporterFunc importer = GetImporter(typeof(JsonData), valueType);
                if (importer != null)
                {
                    valueType = typeof(JsonData);
                }
                ObjectMetadata tdata = AddObjectMetadata(valueType);
                instance = CreateInstance(valueType);
                bool firstRun = true;
                while (!done)
                {
                    if (firstRun)
                    {
                        firstRun = false;
                    }
                    else
                    {
                        reader.Read();
                        if (reader.Token == JsonToken.ObjectEnd)
                        {
                            break;
                        }
                        property = (string)reader.Value;
                    }
                    PropertyMetadata pdata;
                    if (tdata.Properties.TryGetValue(property, out pdata))
                    {
                        // Don't deserialize a field or property that has a JsonIgnore attribute with deserialization usage.
                        if (pdata.Ignore)
                        {
                            ReadSkip(reader);
                            continue;
                        }
                        if (pdata.IsField)
                        {
                            ((FieldInfo)pdata.Info).SetValue(instance, ReadValue(pdata.Type, reader));
                        }
                        else
                        {
                            PropertyInfo pinfo = (PropertyInfo)pdata.Info;
                            if (pinfo.CanWrite)
                            {
                                pinfo.SetValue(instance, ReadValue(pdata.Type, reader), null);
                            }
                            else
                            {
                                ReadValue(pdata.Type, reader);
                            }
                        }
                    }
                    else
                    {
                        if (!tdata.IsDictionary)
                        {
                            if (!reader.SkipNonMembers)
                            {
                                throw new JsonException(string.Format("The type {0} doesn't have the property '{1}'", instType, property));
                            }
                            else
                            {
                                ReadSkip(reader);
                                continue;
                            }
                        }
                        ((IDictionary)instance).Add(property, ReadValue(tdata.ElementType, reader));
                    }
                }
                if (importer != null)
                {
                    instance = importer(instance);
                }
            }
            return(instance);
        }
Ejemplo n.º 2
0
        private static void WriteValue(object obj, JsonWriter writer, bool privateWriter, int depth)
        {
            if (depth > maxNestingDepth)
            {
                throw new JsonException(string.Format("Max allowed object depth reached while trying to export from type {0}", obj.GetType()));
            }
            if (obj == null)
            {
                writer.Write(null);
                return;
            }
            if (obj is IJsonWrapper)
            {
                if (privateWriter)
                {
                    writer.TextWriter.Write(((IJsonWrapper)obj).ToJson());
                }
                else
                {
                    ((IJsonWrapper)obj).ToJson(writer);
                }
                return;
            }
            if (obj is string)
            {
                writer.Write((string)obj);
                return;
            }
            if (obj is double)
            {
                writer.Write((double)obj);
                return;
            }
            if (obj is long)
            {
                writer.Write((long)obj);
                return;
            }
            if (obj is bool)
            {
                writer.Write((bool)obj);
                return;
            }
            if (obj is Array)
            {
                writer.WriteArrayStart();
                Array arr      = (Array)obj;
                Type  elemType = arr.GetType().GetElementType();
                foreach (object elem in arr)
                {
                    // if the collection contains polymorphic elements, we need to include type information for deserialization
                    //if (writer.TypeHinting && elem != null & elem.GetType() != elemType) {
                    //	writer.WriteObjectStart();
                    //	writer.WritePropertyName(writer.HintTypeName);
                    //	writer.Write(elem.GetType().FullName);
                    //	writer.WritePropertyName(writer.HintValueName);
                    //	WriteValue(elem, writer, privateWriter, depth + 1);
                    //	writer.WriteObjectEnd();
                    //} else {
                    WriteValue(elem, writer, privateWriter, depth + 1);
                    //}
                }
                writer.WriteArrayEnd();
                return;
            }
            if (obj is IList)
            {
                writer.WriteArrayStart();
                IList list = (IList)obj;
                // collection might be non-generic type like Arraylist
                Type elemType = typeof(object);
                if (list.GetType().GetGenericArguments().Length > 0)
                {
                    // collection is a generic type like List<T>
                    elemType = list.GetType().GetGenericArguments()[0];
                }
                foreach (object elem in list)
                {
                    // if the collection contains polymorphic elements, we need to include type information for deserialization
                    //if (writer.TypeHinting && elem != null && elem.GetType() != elemType) {
                    //	writer.WriteObjectStart();
                    //	writer.WritePropertyName(writer.HintTypeName);
                    //	writer.Write(elem.GetType().AssemblyQualifiedName);
                    //	writer.WritePropertyName(writer.HintValueName);
                    //	WriteValue(elem, writer, privateWriter, depth + 1);
                    //	writer.WriteObjectEnd();
                    //} else {
                    WriteValue(elem, writer, privateWriter, depth + 1);
                    //}
                }
                writer.WriteArrayEnd();
                return;
            }
            if (obj is IDictionary)
            {
                writer.WriteObjectStart();
                IDictionary dict = (IDictionary)obj;
                // collection might be non-generic type like Hashtable
                Type elemType = typeof(object);
                if (dict.GetType().GetGenericArguments().Length > 1)
                {
                    // collection is a generic type like Dictionary<T, V>
                    elemType = dict.GetType().GetGenericArguments()[1];
                }
                foreach (DictionaryEntry entry in dict)
                {
                    writer.WritePropertyName((string)entry.Key);
                    // if the collection contains polymorphic elements, we need to include type information for deserialization
                    //if (writer.TypeHinting && entry.Value != null && entry.Value.GetType() != elemType) {
                    //	writer.WriteObjectStart();
                    //	writer.WritePropertyName(writer.HintTypeName);
                    //	writer.Write(entry.Value.GetType().AssemblyQualifiedName);
                    //	writer.WritePropertyName(writer.HintValueName);
                    //	WriteValue(entry.Value, writer, privateWriter, depth + 1);
                    //	writer.WriteObjectEnd();
                    //} else {
                    WriteValue(entry.Value, writer, privateWriter, depth + 1);
                    //}
                }
                writer.WriteObjectEnd();
                return;
            }
            Type objType = obj.GetType();
            // Try a base or custom importer if one exists
            ExporterFunc exporter = GetExporter(objType);

            if (exporter != null)
            {
                exporter(obj, writer);
                return;
            }
            // Last option, let's see if it's an enum
            if (obj is Enum)
            {
                Type enumType = Enum.GetUnderlyingType(objType);
                if (enumType == typeof(long))
                {
                    writer.Write((long)obj);
                }
                else
                {
                    ExporterFunc enumConverter = GetExporter(enumType);
                    if (enumConverter != null)
                    {
                        enumConverter(obj, writer);
                    }
                }
                return;
            }
            // Okay, it looks like the input should be exported as an object
            ObjectMetadata tdata = AddObjectMetadata(objType);

            writer.WriteObjectStart();
            //在Json的第一个字段前插入类型标识
            if (writer.TypeHinting)
            {
                writer.WriteType(objType);
            }
            foreach (string property in tdata.Properties.Keys)
            {
                PropertyMetadata pdata = tdata.Properties[property];
                // Don't serialize soft aliases (which get added to ObjectMetadata.Properties twice).
                if (pdata.Alias != null && property != pdata.Info.Name && tdata.Properties.ContainsKey(pdata.Info.Name))
                {
                    continue;
                }
                // Don't serialize a field or property with the JsonIgnore attribute with serialization usage
                if (pdata.Ignore)
                {
                    continue;
                }
                if (pdata.IsField)
                {
                    FieldInfo info = (FieldInfo)pdata.Info;
                    if (pdata.Alias != null)
                    {
                        writer.WritePropertyName(pdata.Alias);
                    }
                    else
                    {
                        writer.WritePropertyName(info.Name);
                    }
                    object value = info.GetValue(obj);
                    //if (writer.TypeHinting && value != null && info.FieldType != value.GetType()) {
                    //	// the object stored in the field might be a different type that what was declared, need type hinting
                    //	writer.WriteObjectStart();
                    //	writer.WritePropertyName(writer.HintTypeName);
                    //	writer.Write(value.GetType().AssemblyQualifiedName);
                    //	writer.WritePropertyName(writer.HintValueName);
                    //	WriteValue(value, writer, privateWriter, depth + 1);
                    //	writer.WriteObjectEnd();
                    //} else {
                    WriteValue(value, writer, privateWriter, depth + 1);
                    //}
                }
                //暂时去除类属性的序列化操作,因为静态数据里面带有不需要序列化的属性
                //else {
                //	PropertyInfo info = (PropertyInfo)pdata.Info;
                //	if (info.CanRead) {
                //		if (pdata.Alias != null) {
                //			writer.WritePropertyName(pdata.Alias);
                //		} else {
                //			writer.WritePropertyName(info.Name);
                //		}
                //		object value = info.GetValue(obj, null);
                //		//if (writer.TypeHinting && value != null && info.PropertyType != value.GetType()) {
                //		//	// the object stored in the property might be a different type that what was declared, need type hinting
                //		//	writer.WriteObjectStart();
                //		//	writer.WritePropertyName(writer.HintTypeName);
                //		//	writer.Write(value.GetType().AssemblyQualifiedName);
                //		//	writer.WritePropertyName(writer.HintValueName);
                //		//	WriteValue(value, writer, privateWriter, depth + 1);
                //		//	writer.WriteObjectEnd();
                //		//} else {
                //			WriteValue(value, writer, privateWriter, depth + 1);
                //		//}
                //	}
                //}
            }
            writer.WriteObjectEnd();
        }
Ejemplo n.º 3
0
        private static ObjectMetadata AddObjectMetadata(Type type)
        {
            if (objectMetadata.ContainsKey(type))
            {
                return(objectMetadata[type]);
            }
            ObjectMetadata data = new ObjectMetadata();

            if (type.GetInterface("System.Collections.IDictionary") != null)
            {
                data.IsDictionary = true;
            }
            data.Properties = new Dictionary <string, PropertyMetadata>();

            // Get all kinds of declared properties
            BindingFlags pflags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;

            foreach (PropertyInfo pinfo in type.GetProperties(pflags))
            {
                if (pinfo.Name == "Item")
                {
                    ParameterInfo[] parameters = pinfo.GetIndexParameters();
                    if (parameters.Length != 1)
                    {
                        continue;
                    }
                    if (parameters[0].ParameterType == typeof(string))
                    {
                        data.ElementType = pinfo.PropertyType;
                    }
                    continue;
                }
                // Include properties automatically that have at least one public accessor
                bool autoInclude =
                    (pinfo.GetGetMethod() != null && pinfo.GetGetMethod().IsPublic) ||
                    (pinfo.GetSetMethod() != null && pinfo.GetSetMethod().IsPublic);
                // If neither accessor is public and we don't have a [JsonInclude] attribute, skip it
                if (!autoInclude && pinfo.GetCustomAttributes(typeof(JsonInclude), true).Count() == 0)
                {
                    continue;
                }
                PropertyMetadata pdata = new PropertyMetadata();
                pdata.Info = pinfo;
                pdata.Type = pinfo.PropertyType;
                object[] ignoreAttrs = pinfo.GetCustomAttributes(typeof(JsonIgnore), true).ToArray();
                if (ignoreAttrs.Length > 0)
                {
                    pdata.Ignore = true;
                }
                object[] aliasAttrs = pinfo.GetCustomAttributes(typeof(JsonAlias), true).ToArray();
                if (aliasAttrs.Length > 0)
                {
                    JsonAlias aliasAttr = (JsonAlias)aliasAttrs[0];
                    if (aliasAttr.Alias == pinfo.Name)
                    {
                        throw new JsonException(string.Format("Alias name '{0}' must be different from the property it represents for type '{1}'", pinfo.Name, type));
                    }
                    if (data.Properties.ContainsKey(aliasAttr.Alias))
                    {
                        throw new JsonException(string.Format("'{0}' already contains the property or alias name '{1}'", type, aliasAttr.Alias));
                    }
                    pdata.Alias = aliasAttr.Alias;
                    if (aliasAttr.AcceptOriginal)
                    {
                        data.Properties.Add(pinfo.Name, pdata);
                    }
                }
                if (pdata.Alias != null)
                {
                    data.Properties.Add(pdata.Alias, pdata);
                }
                else
                {
                    if (data.Properties.ContainsKey(pinfo.Name))
                    {
                        throw new JsonException(string.Format("'{0}' already contains the property or alias name '{1}'", type, pinfo.Name));
                    }
                    data.Properties.Add(pinfo.Name, pdata);
                }
            }
            // Get all kinds of declared fields
            BindingFlags fflags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;

            foreach (FieldInfo finfo in type.GetFields(fflags))
            {
                // If the field isn't public and doesn't have an [Include] attribute, skip it
                if (!finfo.IsPublic && finfo.GetCustomAttributes(typeof(JsonInclude), true).Count() == 0)
                {
                    continue;
                }
                PropertyMetadata pdata = new PropertyMetadata();
                pdata.Info    = finfo;
                pdata.IsField = true;
                pdata.Type    = finfo.FieldType;
                object[] ignoreAttrs = finfo.GetCustomAttributes(typeof(JsonIgnore), true).ToArray();
                if (ignoreAttrs.Length > 0)
                {
                    pdata.Ignore = true;
                }
                object[] aliasAttrs = finfo.GetCustomAttributes(typeof(JsonAlias), true).ToArray();
                if (aliasAttrs.Length > 0)
                {
                    JsonAlias aliasAttr = (JsonAlias)aliasAttrs[0];
                    if (aliasAttr.Alias == finfo.Name)
                    {
                        throw new JsonException(string.Format("Alias name '{0}' must be different from the field it represents for type '{1}'", finfo.Name, type));
                    }
                    if (data.Properties.ContainsKey(aliasAttr.Alias))
                    {
                        throw new JsonException(string.Format("'{0}' already contains the field or alias name '{1}'", type, aliasAttr.Alias));
                    }
                    pdata.Alias = aliasAttr.Alias;
                    if (aliasAttr.AcceptOriginal)
                    {
                        data.Properties.Add(finfo.Name, pdata);
                    }
                }
                if (pdata.Alias != null)
                {
                    data.Properties.Add(pdata.Alias, pdata);
                }
                else
                {
                    if (data.Properties.ContainsKey(finfo.Name))
                    {
                        throw new JsonException(string.Format("'{0}' already contains the field or alias name '{1}'", type, finfo.Name));
                    }
                    data.Properties.Add(finfo.Name, pdata);
                }
            }
            objectMetadata.Add(type, data);
            return(data);
        }