欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

C#序列化和反序列化

程序员文章站 2022-06-16 08:13:44
...

目录

序列化(Serialization)和    反序列化(DeSerialization)

BinaryFormatter和SoapFormatter    

IFormatter

Serializable和NonSerialized

事件响应

ISerializable 自定义序列化


序列化(Serialization)和    反序列化(DeSerialization)

    序列化(Serialization):是将对象的状态信息转换为可以存储或传输的形式的过程。在序列化期间,对象将其当前状态写入到临时或持久性存储区。反序列化是序列化的反向操作,将文件还原为对象。


BinaryFormatter和SoapFormatter    

       .NET提供了一个接口System.Runtime.Serialization.Formatter。定义了实现序列化和反序列化所需的操作,并提供了两个实现接口的类:BinaryFormatterSoapFormatter

BinaryFormatter:用于将对象序列化为二进制数据。

SoapFormatter:用于将对象序列化为人接直接可读的文本格式,这个文本是用SOAP来描述的。(SOAP全称为简单对象访问协议Simple Object Access Protocol)是一种轻量级的,基于XML协议的。在使用SoapFormatter生成文件(相较于BinaryFormatter生成文件)较大(下面有举例)

using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization.Formatters.Soap;

    提示:在使用System.Runtime.Serialization.Formatters.Soap未找到时,可能需要引入System.Runtime.Serialization.Formatters.Soap。

C#序列化和反序列化
 


IFormatter

   IFormatter中最重要的两个方法就是Serialize()和Deserialize(),分别用于序列化和反序列化。IFormatter接受的是Stream基类,所以可以序列化到任何流类型中,而不仅限于文件流。

        //
        // 摘要:
        //     反序列化所提供流中的数据并重新组成对象图形。
        //
        // 参数:
        //   serializationStream:
        //     包含要反序列化的数据的流。
        //
        // 返回结果:
        //     反序列化的图形的*对象。
        object Deserialize(Stream serializationStream);
        //
        // 摘要:
        //     将对象或具有给定根的对象图形序列化为所提供的流。
        //
        // 参数:
        //   serializationStream:
        //     格式化程序在其中放置序列化数据的流。此流可以引用多种后备存储区(如文件、网络、内存等)。
        //
        //   graph:
        //     要序列化的对象或对象图形的根。将自动序列化此根对象的所有子对象。
        void Serialize(Stream serializationStream, object graph);

Serializable和NonSerialized

Serializable:假如你想对某个类进行序列化,需要在定义的类的名字上面加上: [Serializable] ,说明该类是可序列化的,否则将会抛出异常:‘未标记为可序列化’。

NonSerialized:假如你想对某个已标记可序列化类中的某个字段不想序列化,可使用[NonSerialized]标记,在序列化时就会把

它排除在外。需要注意的是NonSerialized只能加在字段上,不能加在属性上。

    [Serializable]//标记该类可序列化
    class NlikiISerializable : ISerializable
    {
        [NonSerialized]//标记该字段不可序列化
        private string _nliki;
    }

事件响应

      对于一些比较敏感的数据(比如账号、密码等),我们不希望他出现在序列化文件中。我们可以使用NonSerialized标记,不过这样的反序列化后对象的状态就不完整了。解决这样的办法可以在序列化前将其进行加密,在反序列化后进行解密还原。在序列化或者反序列化的过程中需要注入一些特定的逻辑。.NET提供了四个序列化和反序列化特性标记来实现这一过程:

OnSerializing(序列化开始前)OnSerialized(序列化开始后)OnDeserializing(反序列化开始前)OnDeserialized(反序列化开始后)

    [Serializable]
    class NlikiSerialize
    {
        [NonSerialized]
        private string _nliki="abc";

        [OnSerializing]
        void OnSerilazing() {
            this._nliki = this._nliki.Replace("a","o");

        }
     }

ISerializable 自定义序列化

自定义序列化只需要实现ISerializable接口就行了。其中SerializationInfo(包含一组AddValue方法和一组Get<Type>方法)有点类似于BinaryWriter和BinaryReader,用于写入和读取对象的属性值。

namespace System.Runtime.Serialization
{
    public interface ISerializable
    {
        void GetObjectData(SerializationInfo info, StreamingContext context);
    }
}

 

简单举例:

namespace ISerializableAuthorNliki
{
    [Serializable]
    class TestISerializable : ISerializable
    {
        [NonSerialized]
        private string[] _strSer;
        public string[] StrSer
        {
            get { return this._strSer; }
            set { this._strSer = value; }
        }
        public TestISerializable() { }
        public void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            info.AddValue("props", _strSer, typeof(string[]));
        }
    }
}
        static void Main(string[] args)
        {
            string path1 = @"C:\Users\YYS\Desktop\Serializable\nliki1.nliki";
            string path2 = @"C:\Users\YYS\Desktop\Serializable\nliki2.nliki";
            TestISerializable test = new TestISerializable();
            string[] str=new string[10000000];
            string st = "I'm Nliki. 中文:南回";
            for (var i=0;i< str.Length; i++) {
                str[i] = st;
            }
            test.StrSer = str;
            IFormatter formatter1 = new BinaryFormatter();
            using (FileStream fs = new FileStream(path1, FileMode.OpenOrCreate))
            {
                formatter1.Serialize(fs, test);
                fs.Close();
            }
            SoapFormatter formatter2 = new SoapFormatter();
            using (FileStream fs = new FileStream(path2, FileMode.OpenOrCreate))
            {
                formatter2.Serialize(fs, test);
                fs.Close();
            }
            Console.ReadKey();
        }

    }

运行结果:

1:生成的文件大小不一样

C#序列化和反序列化

2:可读性不一样(由于文件不好展示,这里就不展示了。nliki1文件人可读性几乎不行;nliki2文件人为可读)