JSON

什麼是JSON

下面的介紹,是我從《百度百科》中搬運過來。詳細的JSON改變你們能夠自行查閱編程

具體的連接地址,我就不放了。(放的話,會被認爲是廣告)json

C#爲咱們提供的第一個操做JSON的類JavaScriptSerializer

該類所屬程序集:ide

System.Web.Extensions

使用時須要添加引用:測試

using System.Web.Script.Serialization;

簡單運用

1.序列化實例this

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.序列化集合lua

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.使屬性不參與序列化spa

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

運行結果code

從截圖能夠看出,Birth沒有參與序列化。orm

複雜運用

不少時候咱們的數據源不是集合,而是DataTable。此時若是咱們直接對其進行序列化,就會拋出循環引用的異常。blog

下面是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>傳遞給序列化的方法便可。

下面是正確的運行結果

感謝閱讀。

相關文章
相關標籤/搜索