什么是JSON
下面的介绍,是我从《百度百科》中搬运过来。详细的JSON改变大家可以自行查阅
具体的链接地址,我就不放了。(放的话,会被认为是广告)
C#为我们提供的第一个操作JSON的类:JavaScriptSerializer
该类所属程序集:
System.Web.Extensions
使用时需要添加引用:
using System.Web.Script.Serialization;
简单运用
1.序列化实例
public class Student { public string ID { get; set; } public string Name { get; set; } public Student() { } public Student(string id, string name) { ID = id; Name = name; } } static void Main(string[] args) { Student student = new Student("stu1","stuName"); //序列化为JSON JavaScriptSerializer js = new JavaScriptSerializer(); string stuJSON = js.Serialize(student); Console.WriteLine("序列化JSON字符串为:{0}", stuJSON); //反序列化为T Student stu1 = js.Deserialize<Student>(stuJSON); Console.WriteLine("ID:{0};Name:{1}", stu1.ID, stu1.Name); }
2.序列化集合
List<Student> lists = new List<Student>() { new Student("1","stu1"), new Student("2","stu2"), new Student("3","stu3") }; JavaScriptSerializer js = new JavaScriptSerializer(); //序列化 string serString = js.Serialize(lists); Console.WriteLine(serString); //反序列化 List<Student> desList = js.Deserialize<List<Student>>(serString); foreach (Student stu in desList) { Console.WriteLine("ID:{0},Name:{1}", stu.ID, stu.Name); }
3.使属性不参与序列化
public class Student { public string ID { get; set; } public string Name { get; set; } //使用该特性,使得Birth不参与序列化 [ScriptIgnore] public DateTime Birth { get; set; } public Student() { } public Student(string id, string name, DateTime birth) { ID = id; Name = name; Birth = birth; } } static void Main(string[] args) { Student stu = new Student("1", "stu1", DateTime.Now.AddYears(-10)); JavaScriptSerializer js = new JavaScriptSerializer(); //序列化 string json = js.Serialize(stu); Console.WriteLine("序列化字符串:{0}", json); Console.WriteLine(""); //反序列化 Console.WriteLine("反序列化"); Student stuDes = js.Deserialize<Student>(json); Console.WriteLine("ID:{0},Name:{1}", stu.ID, stu.Name); }
运行结果
从截图可以看出,Birth没有参与序列化。
复杂运用
很多时候我们的数据源不是集合,而是DataTable。此时如果我们直接对其进行序列化,就会抛出循环引用的异常。
下面是MSDN的介绍
我的猜测是DataTable中的DataRow引用了DataTable(DataRow.Table)从而使得DataTable与DataRow之间循环引用了。
下面是解决序列化DataTable的三种方法,2个扩展方法,1个扩展类
2个扩展方法
public static class JSONHelper { /// <summary> /// 将DataTable转换为List /// </summary> /// <typeparam name="T">转换的类型</typeparam> /// <param name="dataSource">数据源</param> /// <returns>转换得到的List</returns> public static List<T> ToList<T>(this DataTable dataSource) where T : class,new() { Type type = typeof(T); PropertyInfo[] propertyInfos = type.GetProperties(BindingFlags.Public | BindingFlags.Instance); //返回集合 List<T> list = new List<T>(); foreach (DataRow row in dataSource.Rows) { T t = new T(); //循环属性 foreach (PropertyInfo proInfo in propertyInfos) { //通过属性名,得到DataRow数据 if (row[proInfo.Name] != null) { //属性赋值 proInfo.SetValue(t, row[proInfo.Name]); } } list.Add(t); } return list; } /// <summary> /// 将DataTable转换为List(js解析时使用) /// </summary> /// <param name="dataSource">数据源</param> /// <returns></returns> public static List<Dictionary<string, object>> ToList(this DataTable dataSource) { //集合 List<Dictionary<string, object>> list = new List<Dictionary<string, object>>(); foreach (DataRow row in dataSource.Rows) { //实体类 Dictionary<string, object> instance = new Dictionary<string, object>(); foreach (DataColumn col in dataSource.Columns) { //属性 instance.Add(col.ColumnName, row[col.ColumnName]); } list.Add(instance); } return list; } } static void Main(string[] args) { DataTable table = new DataTable(); DataColumn[] cols = new DataColumn[] { new DataColumn("ID", typeof(string)), new DataColumn("Name", typeof(string)), new DataColumn("Birth", typeof(DateTime)) }; table.Columns.AddRange(cols); for (int i = 0; i < 3; i++) { DataRow row = table.NewRow(); row["ID"] = (i + 1).ToString(); row["Name"] = "stu" + i.ToString(); row["Birth"] = DateTime.Now.AddYears(-10).AddDays(i); table.Rows.Add(row); } JavaScriptSerializer js = new JavaScriptSerializer(); string json = string.Empty; #region 扩展方法一 //序列化 Console.WriteLine("扩展方法一"); json = js.Serialize(table.ToList<Student>()); Console.WriteLine(json); Console.WriteLine("\r\n"); //反序列化 List<Student> students = js.Deserialize<List<Student>>(json); foreach (Student stu in students) { Console.WriteLine("ID:{0};Name:{1}", stu.ID, stu.Name); } #endregion Console.WriteLine("\r\n"); #region 扩展方法二 Console.WriteLine("扩展方法二"); json = js.Serialize(table.ToList()); Console.WriteLine(json); #endregion }
1个扩展类
class DataTableConverter : JavaScriptConverter { /// <summary> /// 序列化 /// </summary> /// <param name="obj">需要序列化的数据</param> /// <param name="serializer">序列化操作类</param> /// <returns></returns> public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer) { //需要序列化的数据 DataTable table = obj as DataTable; Dictionary<string, object> result = new Dictionary<string, object>(); result["table"] = table.ToList(); return result; } /// <summary> /// 反序列化 /// </summary> /// <param name="dictionary">反序列化的数据</param> /// <param name="type">反序列化数据的类型</param> /// <param name="serializer">序列化操作类</param> /// <returns></returns> public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer) { if (dictionary == null) throw new ArgumentNullException("dictionary"); if (type == typeof(DataTable)) { foreach (KeyValuePair<string, object> table in dictionary) { //表名 DataTable dt = new DataTable(table.Key); //集合 List<Dictionary<string, object>> list = serializer.ConvertToType<List<Dictionary<string, object>>>(table.Value); //类 Dictionary<string, object> instance = list[0]; //列名 foreach (KeyValuePair<string, object> column in instance) { dt.Columns.Add(column.Key); } //赋值 foreach (Dictionary<string, object> dicItem in list) { DataRow row = dt.NewRow(); foreach (KeyValuePair<string, object> property in dicItem) { row[property.Key] = property.Value; } dt.Rows.Add(row); } return dt; } } return null; } /// <summary> /// 获取本转换器支持的类型 /// </summary> public override IEnumerable<Type> SupportedTypes { get { return new Type[] { typeof(DataTable) }; } } } static void Main(string[] args) { DataTable table = new DataTable(); DataColumn[] cols = new DataColumn[] { new DataColumn("ID", typeof(string)), new DataColumn("Name", typeof(string)) }; table.Columns.AddRange(cols); for (int i = 0; i < 3; i++) { DataRow row = table.NewRow(); row["ID"] = (i + 1).ToString(); row["Name"] = "stu" + i.ToString(); table.Rows.Add(row); } JavaScriptSerializer js = new JavaScriptSerializer(); //序列化 //讲自定义类型注册到转换器中 js.RegisterConverters(new JavaScriptConverter[] { new DataTableConverter() }); string json = js.Serialize(table); Console.WriteLine(json); Console.WriteLine("\r\n"); //反序列化 DataTable desTable = js.Deserialize<DataTable>(json); foreach (DataRow row in desTable.Rows) { Console.WriteLine("ID:{0},Name:{1}", row["ID"], row["Name"]); } }
扩展类,需要继承抽象类:JavaScriptConverter。
重写2个抽象方法
IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
这里重写Serialize方法,我直接调用了之前写好的JSONHelper中的方法。将DataTable转换成了List<Dictionary<string,object>>。然后在重写Deserialize时,就要根据Serialize序列化的类型,来获取数据。在代码中有体现。
1个抽象属性
IEnumerable<Type> SupportedTypes{get;}
在调用时,需要将自定义的类型注册到JavaScriptSerializer中。
C#为我们提供的第二个操作JSON的类:DataContractJsonSerializer
该类所属程序集:
System.Runtime.Serialization
使用时需要添加引用:
System.Runtime.Serialization.Json
需要参与序列化的类需要加上特性:[DataContract],需要参与序列化属性需要加上特性:[DataMember]。
[DataMember(Name="xxx",Order=1)]可以通过Name来指定序列化属性的名称,Order来指定序列化属性的顺序
由于后面介绍复杂的序列化时,需要用到下面的测试代码。所以这里我就全部贴出了。
/// <summary> /// 表单信息 /// </summary> [DataContract] public class Form { /// <summary> /// 版本号 /// </summary> [DataMember(Name = "version", Order = 1)] public string Version { get; set; } /// <summary> /// 标题 /// </summary> [DataMember(Name = "title", Order = 2)] public string Title { get; set; } /// <summary> /// 表单域集合 /// </summary> [DataMember(Name = "fields", Order = 3)] public List<Field> Fields { get; set; } public Form() { Version = string.Empty; Title = string.Empty; Fields = new List<Field>(); } } /// <summary> /// 表单域 /// </summary> [DataContract] public abstract class Field { /// <summary> /// 区域名 /// </summary> [DataMember(Name = "name", Order = 1)] public string Name { get; set; } } /// <summary> /// 标题区域(head区域) /// </summary> [DataContract] public class HeadField : Field { /// <summary> /// 详情 /// </summary> [DataMember(Name = "entrydata", Order = 1)] public List<HeadFieldData> EntryData { get; set; } public HeadField() { this.Name = string.Empty; EntryData = new List<HeadFieldData>(); } } /// <summary> /// 标题区域数据(head区域数据) /// </summary> [DataContract] public class HeadFieldData { /// <summary> /// 名称 /// </summary> [DataMember(Name = "leftfield", Order = 1)] public string LeftField { get; set; } /// <summary> /// 值 /// </summary> [DataMember(Name = "rightfield", Order = 2)] public string RightField { get; set; } }
下面的代码是JSONHelper帮助类
public class JsonHelper { /// <summary> /// JSON序列化 /// </summary> /// <typeparam name="T">序列化的类型</typeparam> /// <param name="t">序列化类型实例</param> /// <param name="knownTypes">扩充可序列化的类型(当面向接口编程时,需要使用)</param> /// <returns></returns> public static string JsonSerializer<T>(T t, IList<Type> knownTypes = null) { string jsonString = string.Empty; DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(T), knownTypes, int.MaxValue, false, null, false); using (MemoryStream ms = new MemoryStream()) { ser.WriteObject(ms, t); jsonString = Encoding.UTF8.GetString(ms.ToArray()); } //替换掉"__type":"xxxxx", string matchingStr = "\"__type\":\"([^\"]+)\","; RegexOptions ops = RegexOptions.Multiline; Regex r = new Regex(matchingStr, ops); if (r.IsMatch(jsonString)) { jsonString = r.Replace(jsonString, ""); } //替换Json的Date字符串 string p = @"\\/Date\((\d+)\+\d+\)\\/"; MatchEvaluator matchEvaluator = new MatchEvaluator(ConvertJsonDateToDateString); Regex reg = new Regex(p); jsonString = reg.Replace(jsonString, matchEvaluator); return jsonString; } /// <summary> /// JSON反序列化 /// </summary> public static T JsonDeserialize<T>(string jsonString) { T obj = default(T); //将"yyyy-MM-dd HH:mm:ss"格式的字符串转为"\/Date(1294499956278+0800)\/"格式 string p = @"\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}"; MatchEvaluator matchEvaluator = new MatchEvaluator(ConvertDateStringToJsonDate); Regex reg = new Regex(p); jsonString = reg.Replace(jsonString, matchEvaluator); DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(T)); using (MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(jsonString))) { obj = (T)ser.ReadObject(ms); } return obj; } /// <summary> /// 将Json序列化的时间由/Date(1294499956278+0800)转为字符串 /// </summary> private static string ConvertJsonDateToDateString(Match m) { string result = string.Empty; DateTime dt = new DateTime(1970, 1, 1); dt = dt.AddMilliseconds(long.Parse(m.Groups[1].Value)); dt = dt.ToLocalTime(); result = dt.ToString("yyyy-MM-dd HH:mm:ss"); return result; } /// <summary> /// 将时间字符串转为Json时间 /// </summary> private static string ConvertDateStringToJsonDate(Match m) { string result = string.Empty; DateTime dt = DateTime.Parse(m.Groups[0].Value); dt = dt.ToUniversalTime(); TimeSpan ts = dt - DateTime.Parse("1970-01-01"); result = string.Format("\\/Date({0}+0800)\\/", ts.TotalMilliseconds); return result; } }
JSONHelper中有一些正则,分别是处理多余的"_type"节点与处理DateTime类型。
下面贴出使用DataContractJsonSerializer的测试代码
static void Main() { string json = string.Empty; Form form = new Form(); form.Version = "1.0"; form.Title = "测试"; HeadField headField = new HeadField(); headField.Name = "测试头数据"; HeadFieldData data1 = new HeadFieldData(); data1.LeftField = "数据1"; data1.RightField = "data1"; headField.EntryData.Add(data1); HeadFieldData data2 = new HeadFieldData(); data2.LeftField = "数据2"; data2.RightField = "data2"; headField.EntryData.Add(data2); HeadFieldData data3 = new HeadFieldData(); data3.LeftField = "数据3"; data3.RightField = "data3"; headField.EntryData.Add(data3); //头信息添加入表单中 form.Fields.Add(headField); //IList<Type> knownTypes = new List<Type>() { typeof(HeadField) }; json = JSONHelper.JsonSerializer<Form>(form); Console.WriteLine(json); }
上面的代码运行后会报错
这段错误信息的意思,代码JSONHelper.JsonSerializer<Form>(form);
只会将数据根据类Form进行序列化,但是Form中包含的HeadField,它不认识,所以报错了。
解决这类问题,只需要将HeadField告诉DataContractJsonSerializer当遇到HeadField的数据时,就按照HeadField进行序列化。
IList<Type> knownTypes = new List<Type>() { typeof(HeadField) }; json = JSONHelper.JsonSerializer<Form>(form, knownTypes); Console.WriteLine(json);
只需要申明一个IList<Type>然后用typeof(HeadField)填充它,最后将IList<Type>传递给序列化的方法即可。
下面是正确的运行结果
感谢阅读。