C#序列化

        序列化是将对象或对象图转换成字节流的过程。反序列化是将字节流转换回对象图的过程。序列化可以用于应用程序状态的保存、剪贴板复制/粘贴对象、对象克隆和网络对象传输等。序列化的方式有:

1) BinaryFormatter 早期的序列化方式,存在安全风险,不推荐使用。

2) BinaryReader/BinaryWriter 二进制读写Primitive Type,并支持字符串读写时的编码设定。

3) XML序列化

4) Json序列化 除了MS提供的库外,Newtonsoft.json非常好用。

        因为BinaryFormatter存在大量的存量使用,做个简单记录。使对象能够通过BinaryFormatter序列化有特性和接口两种实现方式。当特性和接口同时使用时,忽略特性。接口对数据进行完全的控制,且避免使用反射。

1、通过特性实现

[Serializable]
    class Circle
    {
        private double _radius;

        [NonSerialized]
        private double _area;

        public Circle(double radius)
        {
            _radius = radius;
            _area = Math.PI * _radius * _radius;
        }

        public double Area
        {
            get => _area;
        }

        [OnDeserialized]
        private void OnDeserialized(StreamingContext context)
        {
            _area = Math.PI * _radius * _radius;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Circle circle = new(1.2);
            
            Stream stream = SerializeToMemory(circle);
            stream.Position = 0;

            circle = (Circle)DeserializeFromMemory(stream);
        }

        static Stream SerializeToMemory(Circle circle)
        {
            MemoryStream stream = new();
            BinaryFormatter bf = new();
            bf.Serialize(stream, circle);

            return stream;
        }

        static object DeserializeFromMemory(Stream stream)
        {
            BinaryFormatter bf = new();
            return bf.Deserialize(stream);
        }
    }

2、通过接口

除了接口之外,大多数类型还实现了一个特殊的构造器。

[Serializable]
    class Circle : ISerializable, IDeserializationCallback
    {
        private double _radius;
        private double _area;

        public Circle(double radius)
        {
            _radius = radius;
            _area = Math.PI * _radius * _radius;
        }

        [SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter =true)]
        private Circle(SerializationInfo info, StreamingContext context)
        {
            _radius = info.GetDouble("radius");
        }

        public double Area
        {
            get => _area;
        }

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

        public void OnDeserialization(object sender)
        {
            _area = Math.PI * _radius * _radius;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Circle circle = new(1.2);
            
            Stream stream = SerializeToMemory(circle);
            stream.Position = 0;

            circle = (Circle)DeserializeFromMemory(stream);
        }

        static Stream SerializeToMemory(Circle circle)
        {
            MemoryStream stream = new();
            BinaryFormatter bf = new();
            bf.Serialize(stream, circle);

            return stream;
        }

        static object DeserializeFromMemory(Stream stream)
        {
            BinaryFormatter bf = new();
            return bf.Deserialize(stream);
        }
    }

参考:

《CLR via C#》

 Deserialization risks in use of BinaryFormatter and related types | Microsoft Docs