c#示例-json序列化和json树

序列化

由于指针和引用类型的存在,在运行中的程序中,数据不一定是整块的。
可能东一块西一块散落在内存的各个地方。

序列,是指连续且有序的一个整体。序列化就是把数据变为连续有序整体的过程。
经过这样处理后的数据就可以方便的进行传输和储存了。

Json序列化

json格式

json是一种文本数据格式。用键值对的形式表示数据的名字和数据的内容。
在c#中,时间,数字,字符串及其他的基本类型内置了直接和字符串进行转化的方式。
而复杂类型会通过反射拆解他的成员,一直拆解直到只有基本类型为止。

class Weapon
{
	public (int, int) Attack { get; set; }
	public float Speed { get; set; }
	public int Level { get; set; }
}
{
  "Attack": {
    "Item1": 10,
    "Item2": 20
  },
  "Speed": 1.5,
  "Level": 3
}

序列化api

Newtonsoft.Json是c#常用的一个json序列化扩展包。通常他会随着模板项目创建一起引用。
如果没有,引入以下命名空间并右键点击安装Newtonsoft.Json包,VS会自动找到对应的扩展包并下载和引用。

using Newtonsoft.Json;

通过JsonConvert.SerializeObject方法可以将任意类型序列化为json字符串。
但是默认情况下只会序列化属性,不会序列化字段。

Weapon weapon = new Weapon() { Attack = (10, 20), Speed = 1.5f, Level = 3 };
string json = JsonConvert.SerializeObject(weapon);
Console.WriteLine(json);

使用JsonConvert.DeserializeObject方法可以将字符串反序列化为类型实例。
需要使用泛型才能精确判断你的目标类型。

string dejson = @"{""Attack"":{""Item1"":10,""Item2"":20},""Speed"":1.5,""Level"":3}";
Weapon deweapon = JsonConvert.DeserializeObject<Weapon>(dejson);
Console.WriteLine(deweapon.Attack);

反序列化是通过反射进行赋值的。

  • 因此如果json内容里存在一个你的类型没有的属性,这个属性会被忽略。
  • 如果json的内容里不存在你的类型需要的属性,那么这个属性不会被赋值,只会保持默认值。
  • 如果你的属性不具有set访问器,他不会被赋值。
  • 如果你的构造器里有同名的参数,那么会传递参数给构造器,并且之后不会再对属性赋值。

特性控制序列化规则

特性可以在反射的时候被识别到。但是不同的库是识别的特性可能是不同的。

public class Person
{
    // 指定json属性的名称为"name"
    [JsonProperty("name")]
    public string Name { get; set; }

    // 指定json属性的顺序为1
    [JsonProperty(Order = 1)]
    public int Age { get; set; }

    // 指定json属性为null时忽略不写入json中
    [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
    public string Gender { get; set; }
}

详细的特性控制请参阅其他文档。Serialization Attributes

Json树

为了读取json的数据,通常会制作一个实体类,然后反序列化。接着通过类实例获取数据。

{
  "Name": "Alice",
  "Age": 25,
  "Hobbies": [
    "Reading",
    "Cooking",
    "Gaming"
  ]
}

c#示例-json序列化和json树_第1张图片
但如果不想这么做,也可以通过解析为Json类型来读取数据。

Json节点类型

  • JToken:所有json节点的基类
    • Jobject:json对象,用大括号包围的内容,内含多个键值对。
      • JProperty:每一对键值对。包括属性的名字和属性的值。
        • JValue:属性的值。包括Jobject,Jarray,或基本数据类型例如bool,int,string
    • Jarray:json的数组,用中括号包围的内容。里面有一堆并列的值,他们没有名字。

解析json

可以从Jobject,JArray,JToken等类型的静态方法Parse解析字符串。
或者可以通过FromObject序列化一个实例。
解析出来的JToken可以ToString为序列化后的字符串,或者可以ToObject反序列化成实例。

string json = @"{
  ""Name"": ""Alice"",
  ""Age"": 25,
  ""Hobbies"": [
    ""Reading"",
    ""Cooking"",
    ""Gaming""
  ]
}";

var jobject = JObject.Parse(json);
var person = jobject.ToObject<Person>();
jobject = JObject.FromObject(person);
Console.WriteLine(jobject);

public class Person
{
	public string Name { get; set; }
	public int Age { get; set; }
	public string[] Hobbies { get; set; }
}

获取和修改节点内容

Jobject可以通过索引器来获取子节点的内容。
如果是一个字符串,那么会查找子节点中同名的JProperty。
如果是一个int,那么会在Jarray中查找该索引的内容。

string json = @"{
  ""Name"": ""Alice"",
  ""Age"": 25,
  ""Hobbies"": [
    ""Reading"",
    ""Cooking"",
    ""Gaming""
  ]
}";

var jobject = JObject.Parse(json);
var jarr = jobject["Hobbies"];
Console.WriteLine(jarr);
Console.WriteLine(jarr[0]);

可以通过索引器修改节点。但对数组添加内容必须通过添加节点方法。

jobject["Hobbies"][0] = "666";
jobject["Hobbies"][2].AddAfterSelf("14.6");
jobject["Date"] = "2012-4-8";
Console.WriteLine(jobject);

对于基本类型,可以通过强制转化来直接序列化。
如果没有对应的键值对,那么引用类型或可为空值类型的强制转换会得到null。
如果是值类型但没有对应的键值对,或者值无法解析为目标类型,那么会有异常。

jobject["Date"] = "2012-4-8";  
DateTime date = (DateTime)jobject["Date"];
int? age = (int?)jobject["Age"];
string name = (string)jobject["Name"];
Console.WriteLine(date);
Console.WriteLine(age);
Console.WriteLine(name);

你可能感兴趣的:(c#示例,c#)