Ejemplo n.º 1
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.º 2
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);
        }