在用C语言编程的时候,如果要通过网络或者串口等接口传输一个结构体,通常会将这个结构体指针强转成char类型的指针,然后以char类型传输,在另外一边将接收到的数据的指针再转成想要的结构体指针即可。在C#里显然是不能用这种方法操作的。如果用C#编程,可以将需要传输的对象序列化,再另外一边再进行反序列化。
将一个数据进行二进制序列化需要用到的类为:BinaryFormatter,需要引用的命名空间为:System.Runtime.Serialization.Formatters.Binary;
二进制序列化方法:void Serialize(Stream serializationStream, object graph);
该方法的作用是将graph序列化到指定的流。为了测试方便,可以使用FileStream对象(因为FileStream继承自Stream)以文件的形式存储在本地。如果序列化的是一个自定义类对象,那么该类需要用[Serializable]标记,否则程序运行时会抛出异常。
测试代码如下:
using System; using System.Runtime.Serialization.Formatters.Binary; using System.IO; namespace Suzkfly { class Program { static void Main(string[] args) { Person zhangsan = new Person(); BinaryFormatter bf = new BinaryFormatter(); using (FileStream fs = File.Create(@"C:\Users\Suzkfly\Desktop\file_test\1.txt")) { bf.Serialize(fs, zhangsan); } } } [Serializable] public class Person { private int age = 18; private char gender = '男'; private string name = "张三"; } }
程序运行完之后在我传入的那个路径下就出现了1.txt,打开里面的内容大部分是乱码,但能看到里面有age,gender,name这些字符串。
二进制的反序列化就是序列化的逆过程,具体内容就不多说了,直接上测试代码,这次测试使用的1.txt就是上一章生成的,但在代码里我故意使了一些坏:
using System; using System.Runtime.Serialization.Formatters.Binary; using System.IO; namespace Suzkfly { class Program { static void Main(string[] args) { Person zhangsan = new Person(); BinaryFormatter bf = new BinaryFormatter(); using (FileStream fs = File.OpenRead(@"C:\Users\Suzkfly\Desktop\file_test\1.txt")) { zhangsan = (Person)bf.Deserialize(fs); } Console.WriteLine("zhangsan.age = {0}", zhangsan.age); Console.WriteLine("zhangsan.gender = {0}", zhangsan.gender); Console.WriteLine("zhangsan.name = {0}", zhangsan.name); Console.ReadKey(); } } [Serializable] public class Person { public string name; public char gender; public int age; } }
反序列化也要在类上标记[Serializable],不然运行时会抛出异常。代码中我“使坏”的地方有2处,第一是将每个字段的访问修饰符由private改成了public,第二是调换了三个字段的顺序,但是程序的运行结果是喜人的:
但是不能改变类名,否则程序运行时会抛出异常。如果改变了字段名,但是位置不改变,如将"age",改成"egg",那么程序可以正常运行,egg的值不会变成age的值。这说明反序列化是用类名和字段名去精确匹配的,不会受字段的访问级别和顺序的影响。
可以在已经被[Serializable]标记过的类中的字段前,用[NonSerialized]表示这个字段不被序列化(也不能反序列化)。
测试程序:
using System; using System.Runtime.Serialization.Formatters.Binary; using System.IO; namespace Suzkfly { class Program { static void Main(string[] args) { Person zhangsan = new Person(); BinaryFormatter bf = new BinaryFormatter(); using (FileStream fs = File.OpenRead(@"C:\Users\Suzkfly\Desktop\file_test\1.txt")) { zhangsan = (Person)bf.Deserialize(fs); } Console.WriteLine("zhangsan.age = {0}", zhangsan.Age); Console.WriteLine("zhangsan.gender = {0}", zhangsan.Gender); Console.WriteLine("zhangsan.name = {0}", zhangsan.Name); Console.ReadKey(); } } [Serializable] public class Person { private string name; private char gender; [NonSerialized] private int age = 0; public string Name { get { return name; } } public char Gender { get { return gender; } } public int Age { get { return age; } } } }
在该程序中使用的序列化的文件中是有age这个字段的,但是因为运行的程序中age是被[NonSerialized]标记的,因此运行的结果,age的值仍然是0。