1.DataContractJsonSerializer
DataContractJsonSerializer在System.Runtime.Serialization.Json命名空间下,.NETFramework 3.5包含在System.ServiceModel.Web.dll中,需要添加对其的引用;.NETFramework 4在System.Runtime.Serialization中
序列化对象示例:
public class Person
{
public int Age { get; set; }
public string Name { get; set; }
/// <summary>
/// 涉及时间转换问题
/// </summary>
public DateTime BirthDay { get; set; }
/// <summary>
/// Dictionary
/// </summary>
public Dictionary<string, int> Subjects { get; set; }
public Address Adress { get; set; }
/// <summary>
/// 集合类型
/// </summary>
public List<Role> RoleList { get; set; }
/// <summary>
/// 枚举接口
/// </summary>
public IEnumerable<Department> Departments { get; set; }
/// <summary>
/// 数组问题
/// </summary>
public string[] favoriteFruit { get; set; }
}
public class Role
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Address
{
public string Province { get; set; }
public string City { get; set; }
public string District { get; set; }
}
public class Department
{
public int Id { get; set; }
public string Name { get; set; }
}
简单封装下DataContractSerializer,如下:
1. public static class
2. {
3. public static T DeserializeFromString<T>(string str) where T : class
4. {
5. try
6. {
7.
8. byte[] buffer = Encoding.UTF8.GetBytes(str);
9. new
10. new DataContractJsonSerializer(typeof(T));
11. return ser.ReadObject(ms) as
12. }
13. catch
14. {
15. return null;
16. }
17. }
18. public static string SerializeToString<T>(T t) where T : class
19. {
20. try
21. {
22. new DataContractJsonSerializer(typeof(T));
23. string result = string.Empty;
24. using (MemoryStream ms = new
25. {
26. ser.WriteObject(ms, t);
27. result = Encoding.UTF8.GetString(ms.ToArray());
28. }
29.
30. return
31. }
32. catch
33. {
34. return null;
35. }
36. }
37. }
public static class JsonHelper
{
public static T DeserializeFromString<T>(string str) where T : class
{
try
{
byte[] buffer = Encoding.UTF8.GetBytes(str);
MemoryStream ms = new MemoryStream(buffer, 0, buffer.Length);
DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(T));
return ser.ReadObject(ms) as T;
}
catch (Exception e)
{
return null;
}
}
public static string SerializeToString<T>(T t) where T : class
{
try
{
DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(T));
string result = string.Empty;
using (MemoryStream ms = new MemoryStream())
{
ser.WriteObject(ms, t);
result = Encoding.UTF8.GetString(ms.ToArray());
}
return result;
}
catch
{
return null;
}
}
}
序列化代码如下:
1. Person p = new
2. p.Adress = new
3. {
4. "江西",
5. "九江",
6. "D1"
7. };
8. p.Age = 20;
9. p.Name = "张三";
10. p.BirthDay = DateTime.Parse("1990-09-09 09:00:00");
11. p.Subjects = new Dictionary<string, int> { { "java", 99 }, { ".net", 100 } };
12. p.RoleList = new List<Role>() { new Role() { Id = 1, Name = "Role1" }, new Role { Id = 2, Name = "Role2"
13. p.favoriteFruit = new string[] { "apple", "banana"
14. p.Departments = new List<Department>() { new Department() { Id = 1, Name = "DP1" }, new Department() { Id = 2, Name = "DP2"
15. string
Person p = new Person();
p.Adress = new Address
{
Province = "江西",
City = "九江",
District = "D1"
};
p.Age = 20;
p.Name = "张三";
p.BirthDay = DateTime.Parse("1990-09-09 09:00:00");
p.Subjects = new Dictionary<string, int> { { "java", 99 }, { ".net", 100 } };
p.RoleList = new List<Role>() { new Role() { Id = 1, Name = "Role1" }, new Role { Id = 2, Name = "Role2" } };
p.favoriteFruit = new string[] { "apple", "banana" };
p.Departments = new List<Department>() { new Department() { Id = 1, Name = "DP1" }, new Department() { Id = 2, Name = "DP2" } };
string s = JsonHelper.SerializeToString<Person>(p);
结果如下:
以vs中的json格式化工具查看:
问题1:日期时间格式问题,注意序列化后的json字符串(文本形式,vs的json查看器会自动处理日期时间格式),JSON格式不直接支持日期和时间。DateTime值值显示为“Date(652842000000+0800)”形式的JSON字符串,其中第一个数字(在提供的示例中为 Date(652842000000+0800))是 GMT 时区中自 1970 年 1 月 1 日午夜以来按正常时间(非夏令时)经过的毫秒数。该数字可以是负数,以表示之前的时间。示例中包括“+0800”的部分可选,它指示该时间属于Local类型,即它在反序列化时应转换为本地时区。如果没有该部分,则会将时间反序列化为Utc。
解决办法:在序列化和反序列化时,对json字符串中的日期进行处理。修改序列化处理类如下:
1. public static class
2. {
3.
4. public static T DeserializeFromString<T>(string str) where T : class
5. {
6. try
7. {
8. //增加时间处理
9. string p = @"\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}";
10. new
11. str = reg.Replace(str, r =>
12. {
13. string result = string.Empty;
14. DateTime dt = DateTime.Parse(r.Groups[0].Value);
15. dt = dt.ToUniversalTime();
16. "1970-01-01");
17. string.Format("\\/Date({0}+0800)\\/", ts.TotalMilliseconds);
18. return
19. });
20. byte[] buffer = Encoding.UTF8.GetBytes(str);
21. new
22. new DataContractJsonSerializer(typeof(T));
23. return ser.ReadObject(ms) as
24. }
25. catch
26. {
27. return null;
28. }
29. }
30. public static string SerializeToString<T>(T t) where T : class
31. {
32. try
33. {
34. new DataContractJsonSerializer(typeof(T));
35. string result = string.Empty;
36. using (MemoryStream ms = new
37. {
38. ser.WriteObject(ms, t);
39. result = Encoding.UTF8.GetString(ms.ToArray());
40. }
41. // 增加处理时间
42. string p = @"\\/Date(\d+)\+\d+\\/";
43. new
44. result = reg.Replace(result, r =>
45. {
46. string ret = string.Empty;
47. new
48. long.Parse(r.Groups[1].Value));
49. dt = dt.ToLocalTime();
50. "yyyy-MM-dd HH:mm:ss");
51. return
52. });
53. return
54. }
55. catch
56. {
57. return null;
58. }
59. }
60. }
public static class JsonHelper
{
public static T DeserializeFromString<T>(string str) where T : class
{
try
{
//增加时间处理
string p = @"\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}";
Regex reg = new Regex(p);
str = reg.Replace(str, r =>
{
string result = string.Empty;
DateTime dt = DateTime.Parse(r.Groups[0].Value);
dt = dt.ToUniversalTime();
TimeSpan ts = dt - DateTime.Parse("1970-01-01");
result = string.Format("\\/Date({0}+0800)\\/", ts.TotalMilliseconds);
return result;
});
byte[] buffer = Encoding.UTF8.GetBytes(str);
MemoryStream ms = new MemoryStream(buffer, 0, buffer.Length);
DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(T));
return ser.ReadObject(ms) as T;
}
catch (Exception e)
{
return null;
}
}
public static string SerializeToString<T>(T t) where T : class
{
try
{
DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(T));
string result = string.Empty;
using (MemoryStream ms = new MemoryStream())
{
ser.WriteObject(ms, t);
result = Encoding.UTF8.GetString(ms.ToArray());
}
// 增加处理时间
string p = @"\\/Date\((\d+)\+\d+\)\\/";
Regex reg = new Regex(p);
result = reg.Replace(result, r =>
{
string ret = string.Empty;
DateTime dt = new DateTime(1970, 1, 1);
dt = dt.AddMilliseconds(long.Parse(r.Groups[1].Value));
dt = dt.ToLocalTime();
ret = dt.ToString("yyyy-MM-dd HH:mm:ss");
return ret;
});
return result;
}
catch
{
return null;
}
}
}
修改完重新序列化后如下:
测试下反序列化:
1. string s = "{\"Adress\":{\"City\":\"九江\",\"District\":\"D1\",\"Province\":\"江西\"},\"Age\":20,\"BirthDay\":\"1990-09-09 09:00:00\",\"Departments\":[{\"Id\":1,\"Name\":\"DP1\"},{\"Id\":2,\"Name\":\"DP2\"}],\"Name\":\"张三\",\"RoleList\":[{\"Id\":1,\"Name\":\"Role1\"},{\"Id\":2,\"Name\":\"Role2\"}],\"Subjects\":[{\"Key\":\"java\",\"Value\":99},{\"Key\":\".net\",\"Value\":100}],\"favoriteFruit\":[\"apple\",\"banana\"]}";
2.
3. Person p = JsonHelper.DeserializeFromString<Person>(s);
string s = "{\"Adress\":{\"City\":\"九江\",\"District\":\"D1\",\"Province\":\"江西\"},\"Age\":20,\"BirthDay\":\"1990-09-09 09:00:00\",\"Departments\":[{\"Id\":1,\"Name\":\"DP1\"},{\"Id\":2,\"Name\":\"DP2\"}],\"Name\":\"张三\",\"RoleList\":[{\"Id\":1,\"Name\":\"Role1\"},{\"Id\":2,\"Name\":\"Role2\"}],\"Subjects\":[{\"Key\":\"java\",\"Value\":99},{\"Key\":\".net\",\"Value\":100}],\"favoriteFruit\":[\"apple\",\"banana\"]}";
Person p = JsonHelper.DeserializeFromString<Person>(s);
结果如下:
问题2:序列化后的json数据,字符串显示的顺序不对,例如,Age应该处理第一个json属性,现在发现是第二个,另外我们对Age序列化后显示的名称有要求,要显示为PersonAge。这种需求,可以通过Person类运用DataContract和Age属性运用DataMember特性来进行设置,例如我们现在只对Person有要求,修改如下:
1. [DataContract]
2. public class
3. {
4. "PersonAge")]
5. public int Age { get; set; }
6. public string Name { get; set; }
7. public DateTime BirthDay { get; set; }
8. public Dictionary<string, int> Subjects { get; set; }
9. public Address Adress { get; set; }
10. public List<Role> RoleList { get; set; }
11. public IEnumerable<Department> Departments { get; set; }
12. public string[] favoriteFruit { get; set; }
13. }
[DataContract]
public class Person
{
[DataMember(Order = 1, Name = "PersonAge")]
public int Age { get; set; }
public string Name { get; set; }
public DateTime BirthDay { get; set; }
public Dictionary<string, int> Subjects { get; set; }
public Address Adress { get; set; }
public List<Role> RoleList { get; set; }
public IEnumerable<Department> Departments { get; set; }
public string[] favoriteFruit { get; set; }
}
序列化后结果如下:
什么情况?怎么只序列化了一个Peron类中的Age属性?原来当我们使用数据契约(DataContract)来描述的类的序列化时,只有我们显式的把这个类当中的具体的成员通过DataMember来标记了,才表明这个成员是要参与到序列化当中,如果某一个成员没有使用DataMember来标记,表明这个成员不需要参与到序列化当中。因此我们再修改一下:
1. [DataContract]
2. public class
3. {
4. "PersonAge")]
5. public int Age { get; set; }
6. [DataMember(Order = 2)]
7. public string Name { get; set; }
8. [DataMember(Order = 3)]
9. public DateTime BirthDay { get; set; }
10. [DataMember(Order = 4)]
11. public Dictionary<string, int> Subjects { get; set; }
12. [DataMember(Order = 5)]
13. public Address Adress { get; set; }
14. [DataMember(Order = 6)]
15. public List<Role> RoleList { get; set; }
16. [DataMember(Order = 7)]
17. public IEnumerable<Department> Departments { get; set; }
18. [DataMember(Order = 8)]
19. public string[] favoriteFruit { get; set; }
20. }
[DataContract]
public class Person
{
[DataMember(Order = 1, Name = "PersonAge")]
public int Age { get; set; }
[DataMember(Order = 2)]
public string Name { get; set; }
[DataMember(Order = 3)]
public DateTime BirthDay { get; set; }
[DataMember(Order = 4)]
public Dictionary<string, int> Subjects { get; set; }
[DataMember(Order = 5)]
public Address Adress { get; set; }
[DataMember(Order = 6)]
public List<Role> RoleList { get; set; }
[DataMember(Order = 7)]
public IEnumerable<Department> Departments { get; set; }
[DataMember(Order = 8)]
public string[] favoriteFruit { get; set; }
}
结果如下:
问题3:Serializable特性问题,如果我们在Person类中只运用Serializable特性(不运用DataContract)时会发生什么情况,如下:
[Serializable]
public class Person
{
}
序列的结果如下:
要修复这个问题,两个办法,1、去掉Serializable特性,2、在运用Serializable特性的类中额外加上DataContract以及属性中添加DataMember特性。
注意,如果只运用Serializable特性,如果将正常的json字符串反序列,也不能正常反序列化,反序列化的json字段也必须是类似_backingField这种的。
2.JavaScriptSerializer
JSON序列化和反序列化还可以使用JavaScriptSerializer,在System.Web.Script.Serializatioin命名空间下,需引用System.Web.Extensions.dll,简单的封装了下JavaScriptSerializer,如下:
public static class JsonHelper
{
public static string Serializer(object obj)
{
try
{
JavaScriptSerializer ser = new JavaScriptSerializer();
string result = ser.Serialize(obj);
// 增加处理时间
string p = @"\\/Date\((\d+)\)\\/";
Regex reg = new Regex(p);
result = reg.Replace(result, r =>
{
string ret = string.Empty;
DateTime dt = new DateTime(1970, 1, 1);
dt = dt.AddMilliseconds(long.Parse(r.Groups[1].Value));
dt = dt.ToLocalTime();
ret = dt.ToString("yyyy-MM-dd HH:mm:ss");
return ret;
});
return result;
}
catch
{
return null;
}
}
public static T Deserializer<T>(string str)
{
try
{
JavaScriptSerializer ser = new JavaScriptSerializer();
return ser.Deserialize<T>(str);
}
catch
{
return default(T);
}
}
}
序列化对象还使用第1章节中的Person对象,序列化如下:
Person p = new Person();
p.Adress = new Address
{
Province = "江西",
City = "九江",
District = "D1"
};
p.Age = 20;
p.Name = "张三";
p.BirthDay = DateTime.Parse("1990-09-09 09:00:00");
p.Subjects = new Dictionary<string, int> { { "java", 99 }, { ".net", 100 } };
p.RoleList = new List<Role>() { new Role() { Id = 1, Name = "Role1" }, new Role { Id = 2, Name = "Role2" } };
p.favoriteFruit = new string[] { "apple", "banana" };
p.Departments = new List<Department>() { new Department() { Id = 1, Name = "DP1" }, new Department() { Id = 2, Name = "DP2" } };
string s = JsonHelper.Serializer(p);
结果:
问题1:日期时间格式问题与DataContractJsonSerializer一样,同样存在格式问题,处理方式与DataContractJsonSerializer一致。
问题2:JavascriptSerializer和DataContractJsonSerializer有一点不一样,即无DataContract和DataMemeber特性,因此对于JavaScriptSerializer序列化的对象,序列化后的字段名称与对象属性名称是一致的,且无处设置。
问题3:Serializable特性问题,JavaScriptSerializer对于序列化的对象,不考虑序列化对象的Serializable特性问题。因此对于自动属性也不会序列成xx_backingField。
问题4:JavaScriptSerializer可以序列化匿名对象。
1. var o = new { Id = 1, Name = "jack", Address = "China"
2. string
var o = new { Id = 1, Name = "jack", Address = "China" };
string s = JsonHelper.Serializer(o);
结果:
问题5:怎么将字符串反序列化匿名对象呢? 可以使用第三方Newtonsoft.Json。
3.Newtonsoft.Json
Newtonsoft.Json是一款.NET中开源的Json序列化和反序列化类库,可通过http://www.newtonsoft.com/json下载。
该类库中最常用的两个方法:JsonConvert.SerializeObject和JsonConvert.DeserializeObject。
简单的封装下:
1. public static class
2. {
3. public static string Serializer(object
4. {
5. return
6. }
7. public static T Deserializer<T>(string
8. {
9. return
10. }
11. }
public static class JsonHelper
{
public static string Serializer(object obj)
{
return JsonConvert.SerializeObject(obj);
}
public static T Deserializer<T>(string str)
{
return JsonConvert.DeserializeObject<T>(str);
}
}
序列化对象依然引用第1章节中的Person对象,序列化如下:
1. Person p = new
2. new
3. {
4. "江西",
5. "九江",
6. "D1"
7. };
8. p.Age = 20;
9. "张三";
10. "1990-09-09 09:00:00");
11. new Dictionary<string, int> { { "java", 99 }, { ".net", 100 } };
12. new List<Role>() { new Role() { Id = 1, Name = "Role1" }, new Role { Id = 2, Name = "Role2"
13. new string[] { "apple", "banana"
14. new List<Department>() { new Department() { Id = 1, Name = "DP1" }, new Department() { Id = 2, Name = "DP2"
15.
16. string
Person p = new Person();
p.Adress = new Address
{
Province = "江西",
City = "九江",
District = "D1"
};
p.Age = 20;
p.Name = "张三";
p.BirthDay = DateTime.Parse("1990-09-09 09:00:00");
p.Subjects = new Dictionary<string, int> { { "java", 99 }, { ".net", 100 } };
p.RoleList = new List<Role>() { new Role() { Id = 1, Name = "Role1" }, new Role { Id = 2, Name = "Role2" } };
p.favoriteFruit = new string[] { "apple", "banana" };
p.Departments = new List<Department>() { new Department() { Id = 1, Name = "DP1" }, new Department() { Id = 2, Name = "DP2" } };
string s = JsonHelper.Serializer(p);
结果如下:
问题1:日期时间格式问题在Newtonsoft.Json能正常解释,不存在此问题。
问题2:Serializer特性不受影响,与JavascriptSerializer类似。
问题3:将对象反序列化成匿名对象,在JsonHelper类中添加如下方法:
1. public static T DeserializerAnonymousType<T>(string
2. {
3. return
4. }
public static T DeserializerAnonymousType<T>(string str, T t)
{
return JsonConvert.DeserializeAnonymousType<T>(str, t);
}
反序列化成匿名对象示例如下:
var obj = new { Id = 0, Name = "", Address = "" };
string jsonStr = @"{'Id':'1','Name':'zhangsan','Address':'china'}";
obj = JsonHelper.DeserializerAnonymousType(jsonStr, obj);
结果: