序列化是将对象的状态信息转换未可以存储或传输的形式的过程。在序列化期间,对象将其当前状态写入到临时或持久性存储区。以后,可以通过从存储区读取或反序列化对象的状态,重新创建对象。
序列化之前:对象
序列化之后:把对象转换成另一种形式存储
1、二进制序列化器
BinaryFormatter
保存成二进制数据流。
示例:
序列化:
public class Student
{
public Student(int id, string name, int age, string grade)
{
this.ID = id;
this.Name = name;
this.Age = age;
this.Grade = grade;
}
public int ID { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public string Grade { get; set; }
}
`
`
class Program
{
static void Main(string[] args)
{
List<Student> students = new List<Student>();
for (int i = 1; i < 10; i++)
{
Student student = new Student(i, "学生" + i, 18 + i, "年级二");
students.Add(student);
}
FileStream fileStream = new FileStream(@"E:\dotnet\SerilizeAndDeserialize\SerilizeAndDeserialize\data\student.dat", FileMode.OpenOrCreate);
BinaryFormatter bFormat = new BinaryFormatter();
bFormat.Serialize(fileStream, students);
fileStream.Close();
Console.WriteLine("序列化成功");
}
}
`
运行代码,此时会遇到如下图报错;
Student没有标记序列化。
解决方法
[Serializable]
//如果要想保存某个class中的字段,必须在class前面加个这样Attribute
public class Student
{
public Student(int id, string name, int age, string grade)
{
this.ID = id;
this.Name = name;
this.Age = age;
this.Grade = grade;
}
public int ID { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public string Grade { get; set; }
}
之后可以看到成功序列化后,保存至student.dat文件中。
反序列化:
FileStream stream = new FileStream(@"E:\dotnet\SerilizeAndDeserialize\SerilizeAndDeserialize\data\student.dat", FileMode.Open);
BinaryFormatter bdFormat = new BinaryFormatter();
List<Student> students1 = (List<Student>)bFormat.Deserialize(stream);
stream.Close();
Console.WriteLine("反序列化成功");
进一步地:
从 .NET 5.开始,以下 API 标记为已过时
详见:
SYSLIB0011:BinaryFormatter 序列化已过时
解决方法
请考虑使用 JsonSerializer 或 XmlSerializer,而不是 BinaryFormatter。
2、XML序列化器
XmlSerializer
保存成XML文件,但没有其他额外信息。另外需要注意的是,XmlSerializer只能保存public类型的字段,而其他两种类型能保存所有类型的字段。
序列化:
Circle circle = new Circle
{
Radius = 10.1,
BgColor = "Black"
};
XmlDocument xd = new XmlDocument();
using (StringWriter sw = new StringWriter())
{
XmlSerializer xz = new XmlSerializer(circle.GetType());
xz.Serialize(sw, circle);
Console.WriteLine(sw.ToString());
xd.LoadXml(sw.ToString());
xd.Save(@"E:\C#\SerilizeAndDeserialize\SerilizeAndDeserialize\data\circle.xml");
}
反序列化:
Circle circle2 = new Circle();
using (XmlReader reader = XmlReader.Create(@"E:\C#\SerilizeAndDeserialize\SerilizeAndDeserialize\data\circle.xml"))
{
XmlSerializer xz = new XmlSerializer(circle2.GetType());
circle2 = (Circle)xz.Deserialize(reader);
Console.WriteLine(reader.ToString());
}
三、JSON序列化器
Json序列化有很多种方法,这里我们介绍.Net 标准库 System.Text.Json
、System.Runtime.Serialization.Json
和 Newtonsoft 库Newtonsoft.Json
;
System.Text.Json
Circle circle = new Circle
{
Radius = 10.1,
BgColor = "Black"
};
string json = JsonSerializer.Serialize(circle); //序列化
Circle circle2 = JsonSerializer.Deserialize<Circle>(json); //反序列化
Newtonsoft.Json
string json = JsonConvert.SerializeObject(circle); //序列化
Circle circle2 = JsonConvert.DeserializeObject<Circle>(json); //反序列化
System.Runtime.Serialization.Json
DataContractJsonSerializer dataContractJsonSerializer = new DataContractJsonSerializer(typeof(Circle));
using (MemoryStream memoryStream = new MemoryStream())
{
dataContractJsonSerializer.WriteObject(memoryStream, circle);
}
DataContractJsonSerializer dataContractJsonSerializer1 = new DataContractJsonSerializer(typeof(Circle));
MemoryStream memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(jsonText));
Circle result = (Circle)((object)dataContractJsonSerializer1.ReadObject(memoryStream));
Newtonsoft.Json.Linq中的JObject类型
以上例子都是使用强类型进行序列化和反序列操作,但有时也会用到不指定类型而直接操作Json格式数据的情况,此时就需要用位于命名空间ewtonsoft.Json.Linq中的JObject类型的对象:
string jsonStr = @"{""MyNum"": 10,""MyStr"": ""Hello World""}";
JObject jObject = JObject.Parse(jsonStr);
Console.WriteLine(jObject.ToString(Formatting.None)); //{"MyNum":10,"MyStr":"Hello World"}
//打印一条属性的值
Console.WriteLine(jObject["MyStr"].Value<string>()); //Hello World
//添加一条属性
jObject.Add("MyStr2", "HaHa");
//打印当前Json字符串
Console.WriteLine(jObject.ToString(Formatting.None)); //{"MyNum":10,"MyStr":"Hello World","MyStr2":"HaHa"}
四、自定义某个字段/属性的序列化/反序列化规则
当接收到的Json格式字符串与本地已有类型不统一时,需要进行自定义的反序列化过程,反之亦然,例如Json字符串中以字符串"TRUE"表示布尔类型true(不自定义,这个过程依然走的通,只是以此举例),以字符串"FALSE"表示布尔类型false时,需要自定义如下:
/// <summary>
/// 自定义布尔类型数据转换规则
/// </summary>
public class MyBoolConverter : JsonConverter{
private const string TrueStr = "TRUE";
private const string FalseStr = "FALSE";
public override bool CanConvert(Type objectType) => true;
//反序列化
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) {
if (reader.ValueType == typeof(string))
{
if ((string)reader.Value == TrueStr)
{
return true;
}
else {
return false;
}
}
return false;
}
//序列化
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) {
if (value.GetType() == typeof(bool))
{
bool result = (bool)value;
if (result)
{
writer.WriteValue(TrueStr);
}
else {
writer.WriteValue(FalseStr);
}
}
}
}
然后,在需要操作的类型定义中的字段/属性中加入该特性:
private class MyClass{
[JsonConverter(typeof(MyBoolConverter))]
public bool MyBool;
}
此时
string jsonStr = @"{""MyBool"": ""TRUE""}";
MyClass1 myClass = JsonConvert.DeserializeObject<MyClass1>(jsonStr);
Console.WriteLine(myClass.MyBool); //True
Console.WriteLine(JsonConvert.SerializeObject(myClass)); //{"MyBool":"TRUE"}