Object轉化成JSON字串
阿新 • • 發佈:2019-01-30
有關JSON的介紹,請參見http://www.json.org/json-zh.html
對於一個類,其中可能包括field, property,方法不做JSON序列化。我們可以去field和property進行JSON轉化。
模仿反射中的FieldInfo和PropertyInfo, 兩者都繼承於MemberInfo,我們定義三個類,用來儲存field,property的資訊:
JsonMemberInfo.cs
JsonClassInfo.cs
還要指定一個物件中哪些field需要被JSON,以及提供JSON序列化時的控制。我們用到Attribute這個東東:
JsonAttrribute.cs
下面上重頭戲,JSON序列化的實現:
JsonSerializer.cs
值得注意的是物件中巢狀物件需要用到遞迴;對陣列,物件,值,在JSON序列化要區分對待;對特殊字元要轉義。
使用示例:
{'NC':{'NF':'NestClassFiled'}, 'IntegerArray':['1', '2', '3']}
新版本的.net framework中提供了把物件轉成JSON的方法,在一個dll裡,具體叫什麼記不得了,scottegu的blog中提到過。
對於一個類,其中可能包括field, property,方法不做JSON序列化。我們可以去field和property進行JSON轉化。
模仿反射中的FieldInfo和PropertyInfo, 兩者都繼承於MemberInfo,我們定義三個類,用來儲存field,property的資訊:
JsonMemberInfo.cs
- using System;
- namespace ×××.JsonSerializer
- {
- publicclass JsonMemberInfo
- {
- protected JsonAttrribute attribute;
- public
- {
- get
- {
- returnthis.attribute;
- }
- set
- {
- this.attribute = value;
- }
- }
- }
- }
- using System;
- using System.Collections.Generic;
- using System.Text;
- using System.Reflection;
- namespace ×××.JsonSerializer
- {
- publicclass JsonFieldInfo : JsonMemberInfo
- {
- private FieldInfo info;
- public FieldInfo Info
- {
- get
- {
- returnthis.info;
- }
- set
- {
- this.info = value;
- }
- }
- publicstring JsonName
- {
- get
- {
- if ((this.attribute != null) && (this.attribute.JsonName != string.Empty))
- {
- returnthis.attribute.JsonName;
- }
- else
- {
- returnthis.info.Name;
- }
- }
- }
- public JsonFieldInfo(FieldInfo i)
- {
- this.info = i;
- }
- }
- }
- using System;
- using System.Collections.Generic;
- using System.Text;
- using System.Reflection;
- namespace ×××.JsonSerializer
- {
- publicclass JsonPropertyInfo : JsonMemberInfo
- {
- private PropertyInfo info;
- public PropertyInfo Info
- {
- get
- {
- returnthis.info;
- }
- set
- {
- this.info = value;
- }
- }
- publicstring JsonName
- {
- get
- {
- if ((this.attribute != null) && (this.attribute.JsonName != string.Empty))
- {
- returnthis.attribute.JsonName;
- }
- else
- {
- returnthis.info.Name;
- }
- }
- }
- public JsonPropertyInfo(PropertyInfo i)
- {
- this.info = i;
- }
- }
- }
JsonClassInfo.cs
- using System;
- namespace ×××.JsonSerializer
- {
- publicclass JsonClassInfo
- {
- private Type classType;
- private JsonFieldInfo[] fields;
- private JsonPropertyInfo[] properties;
- public JsonClassInfo(Type t)
- {
- if (t == null)
- {
- thrownew Exception("Json Serializer cannot get the type of the object!");
- }
- this.classType = t;
- }
- publicstring ClassName
- {
- get
- {
- returnthis.classType.Name;
- }
- }
- public Type ClassType
- {
- get
- {
- returnthis.classType;
- }
- }
- public JsonFieldInfo[] ClassFields
- {
- get
- {
- returnthis.fields;
- }
- set
- {
- this.fields = value;
- }
- }
- public JsonPropertyInfo[] ClassProperties
- {
- get
- {
- returnthis.properties;
- }
- set
- {
- this.properties = value;
- }
- }
- }
- }
還要指定一個物件中哪些field需要被JSON,以及提供JSON序列化時的控制。我們用到Attribute這個東東:
JsonAttrribute.cs
- using System;
- namespace ×××.JsonSerializer
- {
- [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
- publicclass JsonAttrribute : Attribute
- {
- privatestring name;
- privatebool isIgnore;
- public JsonAttrribute(bool ignore)
- : this(ignore, string.Empty)
- {
- }
- public JsonAttrribute(string name)
- : this(false, name)
- {
- }
- public JsonAttrribute() : base() { }
- public JsonAttrribute(bool ignore, string name)
- {
- this.isIgnore = ignore;
- this.name = name;
- }
- publicstring JsonName
- {
- get
- {
- returnthis.name;
- }
- set
- {
- this.name = value;
- }
- }
- publicbool IsIgnore
- {
- get { returnthis.isIgnore; }
- }
- }
- }
下面上重頭戲,JSON序列化的實現:
JsonSerializer.cs
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using System.Reflection;
- using System.Text;
- namespace ×××.JsonSerializer
- {
- publicclass JsonSerializer
- {
- privateconststring LeftBrace = "{";
- privateconststring RightBrace = "}";
- privateconststring LeftBracket = "[";
- privateconststring RightBracket = "]";
- privateconststring Comma = ", ";
- privatestaticreadonly Type stringType = typeof(string);
- privatestaticreadonly Type dateTimeType = typeof(DateTime);
- privatestaticreadonly Type jsonAttrribute = typeof(JsonAttrribute);
- /// <summary>
- ///
- /// </summary>
- /// <param name="obj"></param>
- /// <returns></returns>
- publicstring Serialize(object obj)
- {
- if (null == obj)
- {
- returnstring.Empty;
- }
- Type objType = obj.GetType();
- #region Serialize an Array
- if (objType.IsArray)
- {
- StringBuilder sb = new StringBuilder();
- sb.Append(LeftBracket);
- IEnumerable enumer = obj as IEnumerable;
- if (enumer != null)
- {
- bool extraComma = false;
- IEnumerator enumrator = enumer.GetEnumerator();
- while (enumrator.MoveNext())
- {
- //recursive serialize object in array
- sb.Append(this.Serialize(enumrator.Current));
- sb.Append(Comma);
- extraComma = true;
- }
- if (extraComma)
- {
- sb.Remove(sb.Length - Comma.Length, Comma.Length);
- }
- }
- sb.Append(RightBracket);
- return sb.ToString();
- }
- #endregion
- if (objType.IsEnum)
- {
- returnstring.Format("'{0}'", obj.ToString());
- }
- if (objType.IsValueType)
- {
- if (objType == dateTimeType)
- {
- returnstring.Format("'{0}'", EscapeCharacter(obj.ToString()));
- }
- // The input object is value type
- if (objType.IsPrimitive)
- {
- // The input object is int, doublt, etc.
- returnstring.Format("'{0}'", EscapeCharacter(obj.ToString()));
- }
- else
- {
- // The input object is struct.
- returnthis.SerializeClassStruct(obj, objType);
- }
- }
- else
- {
- // The input object is not value type
- if (objType == stringType)
- {
- // The input object is string
- returnstring.Format("'{0}'", EscapeCharacter(obj.ToString()));
- }
- elseif (objType.IsClass)
- {
- // The input object is a customize class.
- returnthis.SerializeClassStruct(obj, objType);
- }
- else
- {
- // Ingore delegate and interface.
- returnstring.Empty;
- }
- }
- }
- /// <summary>
- ///
- /// </summary>
- /// <param name="obj"></param>
- /// <returns></returns>
- privatestring SerializeClassStruct(object obj, Type objType)
- {
- StringBuilder sb = new StringBuilder();
- sb.Append(LeftBrace);
- bool extraComma = false;
- string strValue = string.Empty;
- JsonClassInfo classInfo = this.ReflectClassInfo(objType);
- foreach (JsonFieldInfo info in classInfo.ClassFields)
- {
- strValue = GetValue(obj, info.Info, info.JsonName, ref extraComma);
- sb.Append(strValue);
- }
- foreach (JsonPropertyInfo info in classInfo.ClassProperties)
- {
- strValue = GetValue(obj, info.Info, info.JsonName, ref extraComma);
- sb.Append(strValue);
- }
- if (extraComma)
- {
- sb.Remove(sb.Length - Comma.Length, Comma.Length);
- }
- sb.Append(RightBrace);
- return sb.ToString();
- }
- /// <summary>
- ///
- /// </summary>
- /// <param name="objType"></param>
- /// <param name="obj"></param>
- /// <param name="fieldInfo"></param>
- /// <param name="jsonName"></param>
- /// <param name="extraComma"></param>
- /// <returns></returns>
- privatestring GetValue(object obj, FieldInfo info, string jsonName, refbool extraComma)
- {
- object value = null;
- StringBuilder sb = new StringBuilder();
- if (obj == null)
- {
- returnstring.Empty;
- }
- if (info != null)
- {
- value = info.GetValue(obj);
- //According to XmlSerializer, if an object is null, it will NOT be serializered
- if (value != null)
- {
- if (!string.IsNullOrEmpty(jsonName))
- {
- sb.Append(string.Format("'{0}':", this.EscapeCharacter(jsonName)));
- }
- sb.Append(Serialize(value));
- sb.Append(Comma);
- extraComma = true;
- }
- }
- return sb.ToString();
- }
- /// <summary>
- ///
- /// </summary>
- /// <param name="objType"></param>
- /// <param name="obj"></param>
- /// <param name="fieldInfo"></param>
- /// <param name="jsonName"></param>
- /// <param name="extraComma"></param>
- /// <returns></returns>
- privatestring GetValue(object obj, PropertyInfo info, string jsonName, refbool extraComma)
- {
- object value = null;
- StringBuilder sb = new StringBuilder();
- if (info != null)
- {
- try
- {
- value = info.GetValue(obj, null);
- }
- catch
- {
- // in case the property is indexer.
- // It will igorne the indexer
- value = "";
- }
- //According to XmlSerializer, if an object is null, it will NOT be serializered
- if (value != null)
- {
- if (!string.IsNullOrEmpty(jsonName))
- {
- sb.Append(string.Format("'{0}':", this.EscapeCharacter(jsonName)));
- }
- sb.Append(Serialize(value));
- sb.Append(Comma);
- extraComma = true;
- }
- }
- return sb.ToString();
- }
- private JsonClassInfo ReflectClassInfo(Type objType)
- {
- //
- //We could use cache to store reflected object
- //
- FieldInfo[] fields = objType.GetFields(BindingFlags.GetField | BindingFlags.GetProperty | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public);
- JsonClassInfo classInfo = new JsonClassInfo(objType);
- classInfo.ClassFields = new JsonFieldInfo[fields.Length];
- for (int i = 0; i < fields.Length; ++i)
- {
- classInfo.ClassFields[i] = new JsonFieldInfo(fields[i]);
- object[] jsonInfo = fields[i].GetCustomAttributes(jsonAttrribute, true);
- if (jsonInfo != null && jsonInfo.Length > 0)
- {
- JsonAttrribute jAttri = jsonInfo[0] as JsonAttrribute;
- if (jAttri.IsIgnore)
- {
- continue;
- }
- classInfo.ClassFields[i].Attribute = jAttri;
- }
- }
- PropertyInfo[] properties = objType.GetProperties(BindingFlags.GetField | BindingFlags.GetProperty | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public);
- classInfo.ClassProperties = new JsonPropertyInfo[properties.Length];
- for (int i = 0; i < properties.Length; ++i)
- {
- classInfo.ClassProperties[i] = new JsonPropertyInfo(properties[i]);
- object[] jsonInfo = properties[i].GetCustomAttributes(jsonAttrribute, true);
- if (jsonInfo != null && jsonInfo.Length > 0)
- {
- JsonAttrribute jAttri = jsonInfo[0] as JsonAttrribute;
- if (jAttri.IsIgnore)
- {
- continue;
- }
- classInfo.ClassProperties[i].Attribute = jAttri;
- }
- }
- return classInfo;
- }
- /// <summary>
- /// Escape / & '
- /// </summary>
- /// <param name="input"></param>
- /// <returns></returns>
- publicstring EscapeCharacter(string input)
- {
- return input.Replace(@"/", @"//").Replace("'", @"/'");
- }
- }
- }
值得注意的是物件中巢狀物件需要用到遞迴;對陣列,物件,值,在JSON序列化要區分對待;對特殊字元要轉義。
使用示例:
- class Program
- {
- staticvoid Main(string[] args)
- {
- TestClass tc = new TestClass();
- JsonSerializer ser = new JsonSerializer();
- string json = ser.Serialize(tc);
- Console.WriteLine(json);
- }
- }
- class TestClass
- {
- [JsonAttrribute("NC")]
- public NestClass nc = new NestClass();
- //This field will not be serialized because ingore = true
- [JsonAttrribute(true)]
- NestClass ic = new NestClass();
- publicint[] IntegerArray = newint[] {1, 2, 3 };
- //private field will not be serialized
- [JsonAttrribute("PNC")]
- private NestClass pnc = new NestClass();
- }
- class NestClass
- {
- [JsonAttrribute("NF")]
- publicstring NestClassFiled = "NestClassFiled";
- }
{'NC':{'NF':'NestClassFiled'}, 'IntegerArray':['1', '2', '3']}
新版本的.net framework中提供了把物件轉成JSON的方法,在一個dll裡,具體叫什麼記不得了,scottegu的blog中提到過。