一个.NET通用JSON解析/构建类的实现(c#)

时间:2022-01-19 13:00:21

在.NET Framework 3.5中已经提供了一个JSON对象的序列化工具,但是他是强类型的,必须先按JSON对象的格式定义一个类型,并将类型加上JSON序列化特性。本文将试图提供一个高度灵活的JSON通用类型(JsonObject),实现对JSON的解析及序列化。

假设JSON对象内容如下:

隐藏行号复制代码 JSON
  1. {
  2. orders: {
  3. date: '21:31:59',
  4. name: 'Xfrog',
  5. books: [{
  6. name: 'C# 网络核心编程',
  7. publish: '2010-3-24'
  8. }, {
  9. name: 'C#入门经典中文版',
  10. publish: '2009-10-16'
  11. }]
  12.     },
  13. blog: 'http://www.cnblogs.com/xfrog'
  14. }

使用JsonObject来构建,可选择以下三种方式:
方式一:

隐藏行号复制代码 C#
  1. //通过标准构造函数
  2. JsonObject json = new JsonObject();
  3. json["orders"] = new JsonProperty(new JsonObject());
  4. json["blog"] = new JsonProperty("http://www.cnblogs.com/xfrog");
  5. JsonObject config = json.Properties<JsonObject>("orders");
  6. json["orders"]["date"] = new JsonProperty(DateTime.Now.ToLongTimeString());
  7. json["orders"]["name"] = new JsonProperty("Xfrog");
  8. json["orders"]["books"] = new JsonProperty();
  9. JsonProperty book = json["orders"]["books"].Add(new JsonObject());
  10. book["name"] = new JsonProperty("C# 网络核心编程");
  11. book["publish"] = new JsonProperty("2010-3-24");
  12. book = json["orders"]["books"].Add(new JsonObject());
  13. book["name"] = new JsonProperty("C#入门经典中文版");
  14. book["publish"] = new JsonProperty("2009-10-16");


方式二:

隐藏行号复制代码 C#
  1. //通过回调函数简化对象的构建
  2. JsonObject json2 = new JsonObject((a) =>
  3. {
  4.     a["orders"] = new JsonProperty(new JsonObject((b) =>
  5.     {
  6.         b["date"] = new JsonProperty(DateTime.Now.ToLongTimeString());
  7.         b["name"] = new JsonProperty("Xfrog");
  8.         b["books"] = new JsonProperty();
  9.         b["books"].Add(new JsonObject((c) =>
  10.         {
  11.             c["name"] = new JsonProperty("C# 网络核心编程");
  12.             c["publish"] = new JsonProperty("2010-3-24");
  13.         }));
  14.         b["books"].Add(new JsonObject((c) =>
  15.         {
  16.             c["name"] = new JsonProperty("C#入门经典中文版");
  17.             c["publish"] = new JsonProperty("2009-10-16");
  18.         }));
  19.     }));
  20.     a["blog"] = new JsonProperty("http://www.cnblogs.com/xfrog");
  21. });

方式三:

隐藏行号复制代码 C#
  1. //通过字符串构建Json对象
  2. JsonObject newObj = new JsonObject(jsonStr);


获取Json对象属性值的方法,也有三种方式:

隐藏行号复制代码 C#
  1. //通过泛型函数
  2. Console.WriteLine(newObj["orders"].GetValue<JsonObject>()["books"].GetValue<List<JsonProperty>>()[1].GetValue<JsonObject>()["name"].Value);
  3. //通过属性类型对应的属性
  4. Console.WriteLine(newObj["orders"].Object["books"].Items[1].Object["name"].Value);
  5. //如果属性为对象类型,可通过字符串索引简化
  6. Console.WriteLine(newObj["orders"]["books"][1]["name"].Value);


    通用类:代码
    ?
    /*********************************************************** 作者:wHaibo* Email:xfrogcn@163.com* 日期:2010-04-07* 版本:1.0* 说明:Json通用转换类*********************************************************/using System;using System.Collections.Generic;usingSystem.Text;namespaceXfrog.Net{/// <summary>/// 用于构建属性值的回调/// </summary>/// <param name="Property"></param>publicdelegate voidSetProperties(JsonObject Property);/// <summary>/// JsonObject属性值类型/// </summary>publicenum JsonPropertyType{String,Object,Array,Number,Bool,Null}/// <summary>/// JSON通用对象/// </summary>publicclass JsonObject{privateDictionary<String, JsonProperty> _property;publicJsonObject(){this._property =null;}publicJsonObject(String jsonString){this.Parse(refjsonString);}publicJsonObject(SetProperties callback){if(callback != null){callback(this);}}/// <summary>/// Json字符串解析/// </summary>/// <param name="jsonString"></param>privatevoid Parse(refString jsonString){intlen = jsonString.Length;boolpoo = string.IsNullOrEmpty(jsonString);stringpo = jsonString.Substring(0, 1);stringll = jsonString.Substring(jsonString.Length - 1, 1);if(String.IsNullOrEmpty(jsonString) || jsonString.Substring(0, 1) !=
    "{" || jsonString.Substring(jsonString.Length - 1, 1) !="}")
    {thrownew ArgumentException("传入文本不符合Json格式!"+ jsonString);}Stack<Char> stack =new Stack<char>();Stack<Char> stackType =new Stack<char>();StringBuilder sb =new StringBuilder();Char cur;boolconvert = false;boolisValue = false;JsonProperty last =null;for(int i = 1; i <= len - 2; i++){cur = jsonString[i];if(cur == '}'){;}if(cur == ' ' && stack.Count == 0){;}elseif ((cur == '\'' || cur == '\"') && !convert && stack.Count == 0 && !isValue){sb.Length = 0;stack.Push(cur);}elseif ((cur == '\'' || cur == '\"') && !convert && stack.Count > 0 && stack.Peek() == cur && !isValue){stack.Pop();}elseif ( (cur == '[' || cur == '{') && stack.Count == 0){stackType.Push(cur =='[' ? ']' : '}');sb.Append(cur);}elseif ((cur == ']' || cur == '}') && stack.Count == 0 && stackType.Peek() == cur){stackType.Pop();sb.Append(cur);}elseif (cur == ':' && stack.Count == 0 && stackType.Count == 0 && !isValue){last =new JsonProperty();this[sb.ToString()] = last;isValue =true;sb.Length = 0;}elseif (cur == ',' && stack.Count == 0 && stackType.Count == 0){if(last != null){String temp = sb.ToString();last.Parse(reftemp);}isValue =false;sb.Length = 0;}else{sb.Append(cur);}}if(sb.Length > 0 && last != null&& last.Type == JsonPropertyType.Null){String temp = sb.ToString();last.Parse(reftemp);}}/// <summary>/// 获取属性/// </summary>/// <param name="PropertyName"></param>/// <returns></returns>publicJsonProperty this[String PropertyName]{get{JsonProperty result =null;if(this._property !=null && this._property.ContainsKey(PropertyName)){result =this._property[PropertyName];}returnresult;}set{if(this._property ==null){this._property =new Dictionary<string, JsonProperty>(StringComparer.OrdinalIgnoreCase);}if(this._property.ContainsKey(PropertyName)){this._property[PropertyName] = value;}else{this._property.Add(PropertyName, value);}}}/// <summary>/// 通过此泛型函数可直接获取指定类型属性的值/// </summary>/// <typeparam name="T"></typeparam>/// <param name="PropertyName"></param>/// <returns></returns>publicvirtual T Properties<T>(String PropertyName) where T :class{JsonProperty p =this[PropertyName];if(p != null){returnp.GetValue<T>();}returndefault(T);}/// <summary>/// 获取属性名称列表/// </summary>/// <returns></returns>publicString[] GetPropertyNames(){if(this._property ==null)returnnull;String[] keys =null;if(this._property.Count > 0){keys =new String[this._property.Count];this._property.Keys.CopyTo(keys, 0);}returnkeys;}/// <summary>/// 移除一个属性/// </summary>/// <param name="PropertyName"></param>/// <returns></returns>publicJsonProperty RemoveProperty(String PropertyName){if(this._property !=null && this._property.ContainsKey(PropertyName)){JsonProperty p =this._property[PropertyName];this._property.Remove(PropertyName);returnp;}returnnull;}/// <summary>/// 是否为空对象/// </summary>/// <returns></returns>publicbool IsNull(){returnthis._property == null;}publicoverride stringToString(){returnthis.ToString("");}/// <summary>/// ToString.../// </summary>/// <param name="format">格式化字符串</param>/// <returns></returns>publicvirtual stringToString(String format){if(this.IsNull()){return"{}";}else{StringBuilder sb =new StringBuilder();foreach(String key inthis._property.Keys){sb.Append(",");sb.Append(key).Append(": ");sb.Append(this._property[key].ToString(format));}if(this._property.Count > 0){sb.Remove(0, 1);}sb.Insert(0,"{");sb.Append("}");returnsb.ToString();}}}/// <summary>/// JSON对象属性/// </summary>publicclass JsonProperty{privateJsonPropertyType _type;privateString _value;privateJsonObject _object;privateList<JsonProperty> _list;privatebool _bool;privatedouble _number;publicJsonProperty(){this._type = JsonPropertyType.Null;this._value =null;this._object =null;this._list =null;}publicJsonProperty(Object value){this.SetValue(value);}publicJsonProperty(String jsonString){this.Parse(refjsonString);}/// <summary>/// Json字符串解析/// </summary>/// <param name="jsonString"></param>publicvoid Parse(refString jsonString){if(String.IsNullOrEmpty(jsonString)){this.SetValue(null);}else{stringfirst = jsonString.Substring(0, 1);stringlast = jsonString.Substring(jsonString.Length - 1, 1);if(first == "["&& last == "]"){this.SetValue(this.ParseArray(refjsonString));}elseif (first == "{" && last=="}"){this.SetValue(this.ParseObject(refjsonString));}elseif ((first == "'" || first == "\"") && first == last){this.SetValue(this.ParseString(refjsonString));}elseif (jsonString == "true" || jsonString =="false"){this.SetValue(jsonString =="true" ? true : false);}elseif (jsonString == "null"){this.SetValue(null);}else{doubled = 0;if(double.TryParse(jsonString,out d)){this.SetValue(d);}else{this.SetValue(jsonString);}}}}/// <summary>/// Json Array解析/// </summary>/// <param name="jsonString"></param>/// <returns></returns>privateList<JsonProperty> ParseArray(refString jsonString){List<JsonProperty> list =new List<JsonProperty>();intlen = jsonString.Length;StringBuilder sb =new StringBuilder();Stack<Char> stack =new Stack<char>();Stack<Char> stackType =new Stack<Char>();boolconver = false;Char cur;for(int i = 1; i <= len - 2; i++){cur = jsonString[i];if(Char.IsWhiteSpace(cur) && stack.Count == 0){;}elseif ((cur == '\'' && stack.Count == 0 && !conver && stackType.Count == 0) || (cur =='\"' && stack.Count == 0 && !conver && stackType.Count == 0)){sb.Length = 0;sb.Append(cur);stack.Push(cur);}elseif (cur == '\\' && stack.Count > 0 && !conver){sb.Append(cur);conver =true;}elseif (conver == true){conver =false;if(cur == 'u'){sb.Append(newchar[] { cur, jsonString[i + 1], jsonString[i + 2], jsonString[i + 3] });i += 4;}else{sb.Append(cur);}}elseif ((cur == '\'' || cur == '\"') && !conver && stack.Count>0 && stack.Peek() == cur && stackType.Count == 0){sb.Append(cur);list.Add(newJsonProperty(sb.ToString()));stack.Pop();}elseif( (cur == '[' || cur == '{' ) && stack.Count==0 ){if(stackType.Count == 0){sb.Length = 0;}sb.Append( cur);stackType.Push((cur =='[' ? ']' : '}'));}elseif ((cur == ']' || cur == '}') && stack.Count == 0 && stackType.Count>0 && stackType.Peek() == cur){sb.Append(cur);stackType.Pop();if(stackType.Count == 0){list.Add(newJsonProperty(sb.ToString()));sb.Length = 0;}}elseif (cur == ',' && stack.Count == 0 && stackType.Count == 0){if(sb.Length > 0){list.Add(newJsonProperty(sb.ToString()));sb.Length = 0;}}else{sb.Append(cur);}}if(stack.Count > 0 || stackType.Count > 0){list.Clear();thrownew ArgumentException("无法解析Json Array对象!");}elseif (sb.Length > 0){list.Add(newJsonProperty(sb.ToString()));}returnlist;}/// <summary>/// Json String解析/// </summary>/// <param name="jsonString"></param>/// <returns></returns>privateString ParseString(refString jsonString){intlen = jsonString.Length;StringBuilder sb =new StringBuilder();boolconver = false;Char cur;for(int i = 1; i <= len - 2; i++){cur = jsonString[i];if(cur == '\\'&& !conver){conver =true;}elseif (conver == true){conver =false;if(cur == '\\'|| cur == '\"'|| cur == '\''|| cur == '/'){sb.Append(cur);}else{if(cur == 'u'){String temp =new String(newchar[] { cur, jsonString[i + 1], jsonString[i + 2], jsonString[i + 3] });sb.Append((char)Convert.ToInt32(temp, 16));i += 4;}else{switch(cur){case'b':sb.Append('\b');break;case'f':sb.Append('\f');break;case'n':sb.Append('\n');break;case'r':sb.Append('\r');break;case't':sb.Append('\t');break;}}}}else{sb.Append(cur);}}returnsb.ToString();}/// <summary>/// Json Object解析/// </summary>/// <param name="jsonString"></param>/// <returns></returns>privateJsonObject ParseObject(refString jsonString){returnnew JsonObject(jsonString);}/// <summary>/// 定义一个索引器,如果属性是非数组的,返回本身/// </summary>/// <param name="index"></param>/// <returns></returns>publicJsonProperty this[intindex]{get{JsonProperty r =null;if(this._type == JsonPropertyType.Array){if(this._list !=null && (this._list.Count - 1) >= index){r =this._list[index];}}elseif (index == 0){returnthis;}returnr;}}/// <summary>/// 提供一个字符串索引,简化对Object属性的访问/// </summary>/// <param name="PropertyName"></param>/// <returns></returns>publicJsonProperty this[String PropertyName]{get{if(this._type == JsonPropertyType.Object){returnthis._object[PropertyName];}else{returnnull;}}set{if(this._type == JsonPropertyType.Object){this._object[PropertyName] = value;}else{thrownew NotSupportedException("Json属性不是对象类型!");}}}/// <summary>/// JsonObject值/// </summary>publicJsonObject Object{get{if(this._type == JsonPropertyType.Object)returnthis._object;returnnull;}}/// <summary>/// 字符串值/// </summary>publicString Value{get{if(this._type == JsonPropertyType.String){returnthis._value;}elseif (this._type == JsonPropertyType.Number){returnthis._number.ToString();}returnnull;}}publicJsonProperty Add(Object value){if(this._type != JsonPropertyType.Null &&this._type != JsonPropertyType.Array){thrownew NotSupportedException("Json属性不是Array类型,无法添加元素!");}if(this._list ==null){this._list =new List<JsonProperty>();}JsonProperty jp =new JsonProperty(value);this._list.Add(jp);this._type = JsonPropertyType.Array;returnjp;}/// <summary>/// Array值,如果属性是非数组的,则封装成只有一个元素的数组/// </summary>publicList<JsonProperty> Items{get{if(this._type == JsonPropertyType.Array){returnthis._list;}else{List<JsonProperty> list =new List<JsonProperty>();list.Add(this);returnlist;}}}/// <summary>/// 数值/// </summary>publicdouble Number{get{if(this._type == JsonPropertyType.Number){returnthis._number;}else{returndouble.NaN;}}}publicvoid Clear(){this._type = JsonPropertyType.Null;this._value = String.Empty;this._object =null;if(this._list !=null){this._list.Clear();this._list =null;}}publicObject GetValue(){if(this._type == JsonPropertyType.String){returnthis._value;}elseif (this._type == JsonPropertyType.Object){returnthis._object;}elseif (this._type == JsonPropertyType.Array){returnthis._list;}elseif (this._type == JsonPropertyType.Bool){returnthis._bool;}elseif (this._type == JsonPropertyType.Number){returnthis._number;}else{returnnull;}}publicvirtual T GetValue<T>() where T :class{return(GetValue() asT);}publicvirtual voidSetValue(Object value){if(value is String){this._type = JsonPropertyType.String;this._value = (String)value;}elseif (value isList<JsonProperty>){this._list = ((List<JsonProperty>)value);this._type = JsonPropertyType.Array;}elseif (value isJsonObject){this._object = (JsonObject)value;this._type = JsonPropertyType.Object;}elseif (value isbool){this._bool = (bool)value;this._type = JsonPropertyType.Bool;}elseif (value == null){this._type = JsonPropertyType.Null;}else{doubled = 0;if(double.TryParse(value.ToString(),out d)){this._number = d;this._type = JsonPropertyType.Number;}else{thrownew ArgumentException("错误的参数类型!");}}}publicvirtual intCount{get{intc = 0;if(this._type == JsonPropertyType.Array){if(this._list !=null){c =this._list.Count;}}else{c = 1;}returnc;}}publicJsonPropertyType Type{get{ return this._type; }}publicoverride stringToString(){returnthis.ToString("");}publicvirtual stringToString(String format){StringBuilder sb =new StringBuilder();if(this._type == JsonPropertyType.String){sb.Append("'").Append(this._value).Append("'");returnsb.ToString();}elseif (this._type == JsonPropertyType.Bool){returnthis._bool ? "true" : "false";}elseif (this._type == JsonPropertyType.Number){returnthis._number.ToString();}elseif (this._type == JsonPropertyType.Null){return"null";}elseif (this._type == JsonPropertyType.Object){returnthis._object.ToString();}else{if(this._list ==null || this._list.Count == 0){sb.Append("[]");}else{sb.Append("[");if(this._list.Count > 0){foreach(JsonProperty p inthis._list){sb.Append(p.ToString());sb.Append(", ");}sb.Length-=2;}sb.Append("]");}returnsb.ToString();}}}}
    
    

      

    
    

      

直接使用ToString函数,将JsonObject转换为Json字符串:

隐藏行号复制代码 C#
  1. String jsonStr = json.ToString();

注意:

我在重载ToString函数时,并没有将字符串转换为JavsScript字符串类型(即对需要转义的字符的处理),当然,要实现也是极其简单的。另外,对于带String参数的ToString,我也为做特殊处理,感兴趣的朋友可自行实现。