序列化

序列化是将对象状态转换为可保持或传输的格式的过程。 反序列化是将已保存或者传输的格式转换回对象的过程。

内置的序列化

在类或者结构加上SerializableAttribute特征,说明类型为可序列化。

[Serializable]
public class Person
{
    private Int32 age;
    private String name;

    public int Age
    {
        get
        {
            return age;
        }
        set
        {
            age = value;
        }
    }
    public string Name
    {
        get
        {
            return name;
        }
        set
        {
            name = value;
        }
    }
}

序列化过程中使用的是字段的名称,而自动属性生成的字段名称不固定,因此不要使用自动属性。 如果某一个字段不需要被序列化,可以为字段添加NonSerializedAttribute特征。

使用序列化

使用System.Runtime.Serialization.Formatters.Binary.BinaryFormatter类,可以进行二进制的序列化和反序列化。

将对象保存到文件,再读取对象。

using System;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.IO;

class Program
{
    static void Main()
    {
        var person = new Person { Name = "zhangesan", Age = 20 };

        BinaryFormatter formatter = new BinaryFormatter();

        using (var fs = File.OpenWrite("point.dat"))
        {
            formatter.Serialize(fs, person);
        }

        using (var fs = File.OpenRead("point.dat"))
        {
            var person2 = formatter.Deserialize(fs);
        }
    }
}

通过Serialize方法,可以将对象保存到流。 通过Deserialize方法,可以从流中得到对象。 在序列化前,序列化程序不会检查所有字段是否是可序列化的,如果有字段是不可序列化的,序列化将失败,流中的数据也是无效的。因此序列化时建议先序列化到内存,没有错误时,再进行保存或传输。 通过序列化和反序列化,可以实现对象的深拷贝。

自定义序列化过程

上面的序列化是自动实现的过程,可以自定义序列化过程。 自定义序列化需要实现System.Runtime.Serialization.ISerializable接口。 通过ISerializable接口的void GetObjectData(SerializationInfo info, StreamingContext context)自定义序列化过程。 其中的SerializationInfo类包含序列化过程中的数据存储,可以进行数据读写。 需要有一个保护的构造函数,参数和GetObjectData方法一致,自定义反序列化过程。

        [Serializable]
        public class Person : ISerializable
        {
            private Int32 age;
            private String name;

            public int Age
            {
                get
                {
                    return age;
                }
                set
                {
                    age = value;
                }
            }
            public string Name
            {
                get
                {
                    return name;
                }
                set
                {
                    name = value;
                }
            }

            protected Person(SerializationInfo info, StreamingContext context)
            {
                age = info.GetInt32("age");
                name = info.GetString("value");
            }

            public void GetObjectData(SerializationInfo info, StreamingContext context)
            {
                info.AddValue("name", name);
                info.AddValue("age", age);
            }
        }

内置序列化的优缺点

优点

实现简单 支持循环引用

缺点

不支持跨语言

使用建议

如果只是在.NET语言内部使用,是一种比较好的方案;要支持跨语言,可以使用其他格式,比如JSON,XML等。