C# 中对象与Json互转的方法整理笔记

来源:互联网 发布:sql数据库怎么建立 编辑:程序博客网 时间:2024/04/28 05:52

前言

         原先一直做CS的开发,对Json了解不多,最近转做BS后,才接触到了Json。作为后台与前端页面数据交互的基础,Json的地位非常重要,自然而然Json转换方法的重要性也不言面喻。

最开始使用的是同事原来写好的对象转Json的方法,并没有什么问题,不过一次偶然的转换,让我发现这个方法的局限性。当时我尝试将一个包含List属性的对象转成Json,该对象的List属性中有若干个对象,本以为转出来的Json字符串会带着这个属性,同时带着List中的所有对象,可实际转换的结果却是该属性的值——Object。考虑到后面可能也会类似的情况要处理,我打算重写该方法一次性解决这个问题。不过粗略研究代码后却有些犯难,这部分代码涉及到反射和特性的知识,而我对这部分知识还不够了解,尝试了简单的改写后发现实现难度有些大,所以放弃了改写的想法。

既然改写难度大,那么是否可以使用C#自带类库中类和方法呢?抱着这个想法在网上搜到了使用System.Runtime.Serialization.Json命名空间中DataContractJsonSerializer类转换Json的方法。在测试中发现使用这种方法转换存在两个问题:第一,生成的Json字符串中,会将自动化属性包裹在<>k__BackingField的尖括号中,如属性”CreateTime”,转换后会变成”< CreateTime>k__BackingField”;第二,如果对象的属性中有时间类型,则会将该属性的值转换成\/Date(1409752544567+0800)\/类的格式,该格式中的数字是与1970年1月1日的毫秒数之差。解决第一个问题需要使用正则表达式查找替换,解决第二个问题不但需要正则表达式查找出那些数字,还要将其转换成时间。实现起来也很麻烦。

于是我又开始在网上寻找其他的解决方法,又发现使用System.Web.Script.Serialization命名空间下的JavaScriptSerializer也可以实现Json对象的互转。而且在测试中还发现使用这种方法不会将自动化属性被包裹在<>k__BackingField的尖括号中的问题,不过时间转换的问题依然存在。

如果C#自带类库中的类和方法无法方便的实现Json对象的互转,就只能求助于第三方类库了。JsonNet或说是NewtonSoft很快便吸引了我的注意。在测试的时候还出现了个小插曲,我使用从官方地址下载的压缩包中BIN目录下的Net4.0版本的库文件,在程序中执行到JsonConvert.SerializeObject方法的时候提示查找JsonConvert.cs文件。后来我打开源项目重新编译生成库文件后就能正常调用执行了。在测试中发现使用JsonConvert.SerializeObject默认的方法转换出来的Json字符串中,时间格式虽然不是我想要的,也属于格式化后的。接着继续在网上搜索是否有控制时间格式化的方法,终于找到了使用命名空间Newtonsoft.Json.Converters中的IsoDateTimeConverter类对象可以控制时间的格式化。另外测试了对象数组转Json和Json转对象及转对象数组的方法后,确认JsonNet适合使用。

另外在整理JsonNet实现代码的时候,意外发现了LitJson库,比较小巧,据说转换时的效率比较高。简单测试了一下发现它实现了时间默认格式的转换,不过不提供详细的控制,在这点上就不如JsonNet好。

个人感觉Json与对象的互转的技术实现关键在于反射和特性,待到有时间研究到这部分内容时再来深入分析、比较和学习。

以下收录了一些从网上找的解决对象与Json互转的方法,其中也包括处理时间格式化的几种方式,仅供备忘参考。

 

1    解析Json的几种方法

原文地址:http://blog.csdn.net/gaofang2009/article/details/6073029

 

主要类

命名空间

限制

内建LINQ支持

时间格式化支持

DataContractJsonSerializer

System.Runtime.Serialization.Json

通用

JavaScriptSerializer

System.Web.Script.Serialization

只能在Web环境使用

JsonArrayJsonObjectJsonValue

System.Json

只能在Silverlight中使用

未知

JsonConvertJArrayJObjectJValueJProperty

Newtonsoft.Json

通用

JsonMapper

LitJson

通用

未知

 

1.1         准备数据

 

实体类:

[csharp] view plain copy
print?
  1. usingSystem.Runtime.Serialization;  
  2.   
  3.    
  4.   
  5. namespace WindowsFormsApplication1  
  6.   
  7. {  
  8.   
  9.     [DataContract]  
  10.   
  11.     public class Person  
  12.   
  13.     {  
  14.   
  15.         [DataMember(Order= 0, IsRequired =true)]  
  16.   
  17.         public string Name { getset; }  
  18.   
  19.    
  20.   
  21.         [DataMember(Order= 1)]  
  22.   
  23.         public int Age { getset; }  
  24.   
  25.    
  26.   
  27.         [DataMember(Order= 2)]  
  28.   
  29.         public bool Alive { getset; }  
  30.   
  31.    
  32.   
  33.         [DataMember(Order= 3)]  
  34.   
  35.         public string[] FavoriteFilms { get;set; }  
  36.   
  37.    
  38.   
  39.         [DataMember(Order= 4)]  
  40.   
  41.         public Person Child { get;set; }  
  42.   
  43.     }  
  44.   
  45. }  

定义:

 

        Action<object> log = o =>Console.WriteLine(o);

        Func<int,int,int> add = (x, y) => x + y;

 

        var p1 = newPerson

        {

            Age = 12,

            Alive = true,

            Name = "lj",

            FavoriteFilms = new[] {"Up","Avatar" }

        };

        var p2 = newPerson() { Age = 28, Name ="cy", Child = p1 };

            

 

1.2         使用DataContractJsonSerializer

 

帮助类:

 

    // usingSystem.Runtime.Serialization.Json;

 

    ///<summary>

    ///解析JSON,仿Javascript风格

    ///</summary>

    public static class JsonTool1

    {

 

        public static T parse<T>(stringjsonString)

        {

            using(var ms =newMemoryStream(Encoding.UTF8.GetBytes(jsonString)))

            {

                return(T)newDataContractJsonSerializer(typeof(T)).ReadObject(ms);

            }

        }

 

        public static stringstringify(object jsonObject)

        {

            using(var ms =newMemoryStream())

            {

                newDataContractJsonSerializer(jsonObject.GetType()).WriteObject(ms,jsonObject);

                returnEncoding.UTF8.GetString(ms.ToArray());

            }

        }

    }

 

用法:

 

   // 序列化

   var jsonString = JSON.stringify(new[] { p1, p2 });

   log(jsonString == JSON.stringify(new List<Person>() { p1, p2}));   //true

   log(jsonString);

   // 反序列化,泛型集合

   JSON.parse<List<Person>>(jsonString);

    // 数组转换            

   JSON.parse<Person[]>(jsonString);

 

输出:

 

[{"Name":"lj","Age":12,"Alive":true,"FavoriteFilms":["Up","Avatar"],"Child":null

},{"Name":"cy","Age":28,"Alive":false,"FavoriteFilms":null,"Child":{"Name":"lj",

"Age":12,"Alive":true,"FavoriteFilms":["Up","Avatar"],"Child":null}}]

 

1.3         使用JavaScriptSerializer

 

   // using System.Web.Script.Serialization;

    

   var jser    = newJavaScriptSerializer();

   var json    = jser.Serialize(newList<Person>() { p1, p2 });

   var persons = jser.Deserialize<List<Person>>(json);

 

1.4         使用Silverlight

 

   // using System.Json

    

   var css = "{ /"#header/" :{background:/"red/"}, layout : [5,4,1],color:/"cyan/"}";

    

   var style = JsonObject.Parse(css) as JsonObject;    

     

    (

   from s in style

   where s.Key == "color"

   select (string)s.Value

   ).First().ToString();    

   // "cyan"

    

    

   // 更多操作

   style["layout"][0] = 22;

    

   var hd = style["#header"];

   style["body>div+p"] = hd;

   style.Remove("#header");

    

   var bd = new JsonObject();

   bd["border"] = "1px solid cyan";

   style["body>div+p"]["#meta"] = bd;

   style.ToString();    

   //{"layout":[22,4,1],"color":"cyan","body>div+p":{"background":"red","#meta":{"border":"1pxsolid cyan"}}}

 

1.5         使用JSON.NET

 

   // using Newtonsoft.Json;

    

   var json = JsonConvert.SerializeObject(new[] { p1, p2 });

   var persons =JsonConvert.DeserializeObject<List<Person>>(json);

   var ja = JArray.Parse(jsonString);            

   log(ja);    //注意,格式化过的输出

 

输出:

 

[

  {

   "Name": "lj",

   "Age": 12,

   "Alive": true,

   "FavoriteFilms": [

     "Up",

     "Avatar"

   ],

   "Child": null

  },

  {

   "Name": "cy",

   "Age": 28,

   "Alive": false,

   "FavoriteFilms": null,

   "Child": {

     "Name": "lj",

     "Age": 12,

     "Alive": true,

     "FavoriteFilms": [

       "Up",

       "Avatar"

     ],

     "Child": null

    }

  }

]

 

LINQ:

 

   var ageCount = ja.Select(j => (int)j["Age"]).Aggregate(add);    

   var q = from j in ja

           where !j["Name"].Value<string>().Equals("lj")

           select (int)j["Age"];

    

   log(q.Aggregate(add) == ageCount); //false

 

其他:

 

   // 与Linq to XML 相似的嵌套构造函数:

   var jo = new JObject(

                    newJProperty("age", persons.Select( p => p.Age)),

                    newJProperty("funny", true),

                    newJProperty("array", new JArray(new[] { 2, 4, 1 }))

                    );

   log(jo);

     

   // JObject 操作

   var css = "{ /"#header/" :{background:/"red/"}, layout : [5,4,1] }";

   var style = JObject.Parse(css);

 

   var bd = new JObject();

   bd["color"] = "1px solid cyan";

 

   style["border"] = bd;

 

   var hd = style["#header"];

   style["body>div+p"] = hd;

 

   hd.Parent.Remove();

 

   style["layout"][0] = 22;

   log(style);

 

输出:

 

    {

     "age": [

       12,

       28

     ],

     "funny": true,

     "array": [

       2,

       4,

       1

     ]

    }

    {

     "layout": [

       22,

       4,

       1

     ],

     "border": {

       "color": "1px solid cyan"

     },

     "body>div+p": {

       "background": "red"

     }

    }

 

 

来自:http://www.mzwu.com/article.asp?id=1913

 

1.6         参考网上的例子自己实现的一个封装JsonNet的类,可控制时间的格式化

参考文章地址:http://de.cel.blog.163.com/blog/static/514512362011214105533226/

 

    ///<summary>

    ///主要使用了Newtonsoft.Json使用了对象与Json字符串之间的互转

    ///</summary>

    public class JsonToolEx

    {

        public static string ToJson(object obj,stringdateTimeFormat ="yyyy-MM-dd")

        {

            IsoDateTimeConvertertimeConverter =newIsoDateTimeConverter();

            timeConverter.DateTimeFormat =dateTimeFormat;

            returnJsonConvert.SerializeObject(obj,timeConverter);

        }

 

        public static T ToObject<T>(stringjson)

        {

            returnJsonConvert.DeserializeObject<T>(json);

        }

    }

 

 

1.7         使用LitJson

 

    public class JsonToolLit

    {

        public static string ToJson(object obj)

        {

            returnJsonMapper.ToJson(obj);

        }

 

        public static T ToObject<T>(stringjson)

        {

            returnJsonMapper.ToObject<T>(json);

        }

    }

 

2    解决json日期格式问题的3种方法

 

原文地址:http://www.jb51.net/article/46456.htm

 

开发中有时候需要从服务器端返回json格式的数据,在后台代码中如果有DateTime类型的数据使用系统自带的工具类序列化后将得到一个很长的数字表示日期数据,如下所示:

 

复制代码代码如下:

 

//设置服务器响应的结果为纯文本格式

           context.Response.ContentType = "text/plain";

          //学生对象集合

           List<Student> students = new List<Student>

           {

                new Student(){Name ="Tom",

                    Birthday=Convert.ToDateTime("2014-01-31 12:12:12")},

                new Student(){Name="Rose",

                    Birthday=Convert.ToDateTime("2014-01-10 11:12:12")},

                new Student(){Name="Mark",

                    Birthday=Convert.ToDateTime("2014-01-09 10:12:12")}

           };

 

           //javascript序列化器

           JavaScriptSerializer jss=new JavaScriptSerializer();

          //序列化学生集合对象得到json字符

           string studentsJson=jss.Serialize(students);

          //将字符串响应到客户端

           context.Response.Write(studentsJson);

          context.Response.End();

 

运行结果是:

 

其中Tom所对应生日“2014-01-31”变成了1391141532000,这其实是1970 年 1 月 1 日至今的毫秒数;1391141532000/1000/60/60/24/365=44.11年,44+1970=2014年,按这种方法可以得出年月日时分秒和毫秒。这种格式是一种可行的表示形式但不是普通人可以看懂的友好格式,怎么让这个格式变化?

 

解决办法:

 

2.1         在服务器端将日期格式使用Select方法或LINQ表达式转换后发到客户端:

 

using System;

using System.Collections.Generic;

using System.Web;

 

using System.Web.Script.Serialization;

 

namespace JsonDate1

{

   using System.Linq;

 

   /// <summary>

   /// 学生类,测试用

   /// </summary>

   public class Student

    {

       /// <summary>

       /// 姓名

       /// </summary>

       public String Name { get; set; }

 

       /// <summary>

       /// 生日

       /// </summary>

       public DateTime Birthday { get; set; }

    }

 

   /// <summary>

   /// 返回学生集合的json字符

   /// </summary>

   public class GetJson : IHttpHandler

    {

       public void ProcessRequest(HttpContext context)

       {

           //设置服务器响应的结果为纯文本格式

           context.Response.ContentType = "text/plain";

           //学生对象集合

           List<Student> students = new List<Student>

           {

                new Student(){Name="Tom",Birthday =Convert.ToDateTime("2014-01-31 12:12:12")},

                new Student(){Name="Rose",Birthday =Convert.ToDateTime("2014-01-1011:12:12")},

                new Student(){Name="Mark",Birthday =Convert.ToDateTime("2014-01-0910:12:12")}

           };

 

           //使用Select方法重新投影对象集合将Birthday属性转换成一个新的属性

           //注意属性变化后要重新命名,并立即执行

           var studentSet =

                students.Select

                (

                p => new { p.Name, Birthday= p.Birthday.ToString("yyyy-mm-dd") }

                ).ToList();

 

           //javascript序列化器

           JavaScriptSerializer jss = new JavaScriptSerializer();

           //序列化学生集合对象得到json字符

           string studentsJson = jss.Serialize(studentSet);

           //将字符串响应到客户端

           context.Response.Write(studentsJson);

           context.Response.End();

       }

 

       public bool IsReusable

       {

           get

           {

                return false;

           }

       }

    }

}

 

Select方法重新投影对象集合将Birthday属性转换成一个新的属性,注意属性变化后要重新命名,属性名可以相同;这里可以使用select方法也可以使用LINQ查询表达式,也可以选择别的方式达到相同的目的;这种办法可以将集合中客户端不用的属性剔除,达到简单优化性能的目的。

 

运行结果:

 

这时候的日期格式就已经变成友好格式了,不过在javascript中这只是一个字符串。

 

2.2         方法二:在javascript处理

 

在javascript中将"Birthday":"\/Date(1391141532000)\/"中的字符串转换成javascript中的日期对象,可以将Birthday这个Key所对应的Value中的非数字字符以替换的方式删除,到到一个数字1391141532000,然后实例化一个Date对象,将1391141532000毫秒作为参数,得到一个javascript中的日期对象,代码如下:

 

<!DOCTYPE html>

<htmlxmlns="http://www.w3.org/1999/xhtml">

<head>

   <title>json日期格式处理</title>

   <script src="Scripts/jquery-1.10.2.min.js"type="text/javascript"></script>

   <script type="text/javascript">

       $(function() {

           $.getJSON("getJson.ashx", function (students) {

                $.each(students, function(index, obj) {

                   $("<li/>").html(obj.Name).appendTo("#ulStudents");

 

                    //使用正则表达式将生日属性中的非数字(\D)删除

                    //并把得到的毫秒数转换成数字类型

                    var birthdayMilliseconds =parseInt(obj.Birthday.replace(/\D/igm, ""));

                    //实例化一个新的日期格式,使用1970 年 1 月 1 日至今的毫秒数为参数

                    var birthday = newDate(birthdayMilliseconds);

 

                   $("<li/>").html(birthday.toLocaleString()).appendTo("#ulStudents");;

                });

           });

       });

   </script>

</head>

<body>

   <h2>json日期格式处理</h2>

   <ul id="ulStudents">

   </ul>

</body>

</html>

 

运行结果:

 

上的使用正则/\D/igm达到替换所有非数字的目的,\D表示非数字,igm是参数,分别表示忽视(ignore)大小写;多次、全局(global)替换;多行替换(multi-line);有一些时候还会出现+86的情况,只需要变换正则同样可以达到目的。另外如果项目中反复出现这种需要处理日期格式的问题,可以扩展一个javascript方法,代码如下:

 

$(function () {

           $.getJSON("getJson.ashx", function (students) {

                $.each(students, function(index, obj) {

                 $("<li/>").html(obj.Name).appendTo("#ulStudents");

 

                  //使用正则表达式将生日属性中的非数字(\D)删除

                    //并把得到的毫秒数转换成数字类型

                    var birthdayMilliseconds =parseInt(obj.Birthday.replace(/\D/igm, ""));

                  //实例化一个新的日期格式,使用1970 年 1 月 1 日至今的毫秒数为参数

                    var birthday = newDate(birthdayMilliseconds);

 

                  $("<li/>").html(birthday.toLocaleString()).appendTo("#ulStudents");

                 $("<li/>").html(obj.Birthday.toDate()).appendTo("#ulStudents");

                });

           });

       });

 

       //在String对象中扩展一个toDate方法,可以根据要求完善

       String.prototype.toDate = function () {

           var dateMilliseconds;

           if (isNaN(this)) {

                //使用正则表达式将日期属性中的非数字(\D)删除

                dateMilliseconds=this.replace(/\D/igm, "");

           } else {

                dateMilliseconds=this;

            }

           //实例化一个新的日期格式,使用1970 年 1 月 1 日至今的毫秒数为参数

           return new Date(parseInt(dateMilliseconds));

       };

 

上面扩展的方法toDate不一定合理,也不够强大,可以根据需要修改。

 

2.3         方法三:选择一些第三方的json工具类

 

可以选择一些第三方的json工具类,其中不乏有一些已经对日期格式问题已处理好了的,常见的json序列化与反序列化工具库有:

 

1.fastJSON.

2.JSON_checker.

3.Jayrock.

4.Json.NET - LINQ to JSON.

5.LitJSON.

6.JSON for .NET.

7.JsonFx.

8.JSONSharp.

9.JsonExSerializer.

10.fluent-json

11.Manatee Json

 

这里以litjson为序列化与反序列化json的工具类作示例,代码如下:

 

复制代码代码如下:

 

using System;

using System.Collections.Generic;

using System.Web;

 

using LitJson;

 

namespace JsonDate2

{

   using System.Linq;

 

   /// <summary>

   /// 学生类,测试用

   /// </summary>

   public class Student

    {

       /// <summary>

       /// 姓名

       /// </summary>

       public String Name { get; set; }

 

       /// <summary>

       /// 生日

       /// </summary>

       public DateTime Birthday { get; set; }

    }

 

   /// <summary>

   /// 返回学生集合的json字符

   /// </summary>

   public class GetJson : IHttpHandler

    {

       public void ProcessRequest(HttpContext context)

       {

           //设置服务器响应的结果为纯文本格式

           context.Response.ContentType = "text/plain";

           //学生对象集合

           List<Student> students = new List<Student>

           {

                new Student(){Name="Tom",Birthday =Convert.ToDateTime("2014-01-3112:12:12")},

                new Student(){Name="Rose",Birthday =Convert.ToDateTime("2014-01-1011:12:12")},

                new Student(){Name="Mark",Birthday =Convert.ToDateTime("2014-01-0910:12:12")}

           };

 

           //序列化学生集合对象得到json字符

           string studentsJson = JsonMapper.ToJson(students);

           //将字符串响应到客户端

           context.Response.Write(studentsJson);

           context.Response.End();

       }

 

       public bool IsReusable

       {

           get

           {

                return false;

           }

       }

    }

}

 

运行结果如下:

 

这时候的日期格式就基本正确了,只要在javascript中直接实例化日期就好了,

 

var date = new Date("01/31/201412:12:12");

alert(date.toLocaleString());

 

客户端的代码如下:

 

复制代码代码如下:

 

$(function () {

           $.getJSON("GetJson2.ashx", function (students) {

                $.each(students, function(index, obj) {

                   $("<li/>").html(obj.Name).appendTo("#ulStudents");

 

                    var birthday = newDate(obj.Birthday);

                   $("<li/>").html(birthday.toLocaleString()).appendTo("#ulStudents");

                });

           });

       });

 

       var date = new Date("01/31/2014 12:12:12");

       alert(date.toLocaleString());

原创粉丝点击