什么是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);
}
View Code

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);
}
View Code

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);
}
View Code

运行结果

从截图可以看出,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
}
View Code

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"]);
    }
}
View Code

扩展类,需要继承抽象类: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; }
}
View Code

下面的代码是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;
    }
}
View Code

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);
}
View Code

上面的代码运行后会报错

 

这段错误信息的意思,代码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>传递给序列化的方法即可。

下面是正确的运行结果

感谢阅读。

posted on 2014-04-02 11:34  安静生活  阅读(2140)  评论(0编辑  收藏  举报