C#_Serialize和Deserialize

C#_Serialize和Deserialize

一、概念

序列化是通过将对象转换为字节流,从而存储对象或将对象传输到内存、数据库或文件的过程。主要用途是保存对象的状态,包括对象的数据,以便能够在需要时重建对象。反向过程称为反序列化。

Object Bytes Database Memory File

如上图所示,对象object被序列化为字节流,其中不仅包括数据、还包括对象类型的相关信息,如版本、区域性和程序集名称。然后可以将此流中的内容存储到数据库中、文件或内存中。

二、序列化的三种类型

  • 二进制。就是字节流可以存储在本地文件中或者socket网络流等
  • XML。存储为XML文件
  • Json。存储为Json文件

在这里我们重点介绍一下二进制类型的相关问题。XML和Json很类似,后期会侧重介绍Json。

三、二进制序列化后的字节流中到底是什么?

要想知道这个问题,我们就写一个小Demo。将一个对象进行二进制序列后存储为文件。

    public class Person
    {
        public string Name { get; set; }

        public uint Age { get; set; }

        public UInt16[] Data { get; set; }
    }

首先自定义一个类,但是这样的类时不可以直接被序列化的,必须要在类上加一个[Serialize]特性。如果类中还有其他自定义类型的字段,那么该类型也需要加上[Serialize]特性

    [Serializable]
    public class Person
    {
        public string Name { get; set; }

        private uint age;
        public uint Age 
        {
            get { return age; }
            set { age = value; }
        }

        public UInt16[] Data { get; set; }
    }

因为默认情况下,会序列化类中的所有字段,如果需要忽视不需要序列化也需要加上[NonSerialized]特性。注意,这个特性只能加在字段上。

[Serializable]
public class Person
{
    public string Name { get; set; }

    [NonSerialized]
    private uint age;
    public uint Age 
    {
        get { return age; }
        set { age = value; }
    }

    public UInt16[] Data { get; set; }
}

接下来进行序列化也反序列化:

            Person p = new Person
            {
                Name = "zhanghanyun",
                Age = 0x18,
                Data = new UInt16[] { 0x11, 0x22, 0x33, 0x44, 0x55 },
            };
            using (FileStream fs = new FileStream(@"Person.dat",FileMode.Create))
            {
                BinaryFormatter formatter = new BinaryFormatter();
                formatter.Serialize(fs, p);
            }

            using (FileStream fs = new FileStream(@"Person.dat",FileMode.Open))
            {
                BinaryFormatter formatter = new BinaryFormatter();
                Person p1 = (Person)formatter.Deserialize(fs);   
            }

代码也挺简单的,主要用到了BinaryFormatter类,它有Serialize()方法和Deserialize()方法,这两个方法都需要一个Stream类型,我们示例中使用的FileStream因为需要存储本地文件,也可以使用MemoryStream。

接下来我们看看那个二进制文件

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oMJ2vxYs-1609411109383)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20201231160135527.png)]

在这个文件中,我们果然看到了我们定义的Name,还有Data。Age由于被ignore了,所以在文件中找不到。但除了这些字段,还有版本、区域性和程序集名称等信息保存了。

所以,如果我们直接将对象序列化然后再通过网络流传送(用户数据域一般还会自定义协议)给其他进程,是非常不合适的。因为自定义协议可能只需要我们的字段字节流。

四、字节流的顺序和类中字段的顺序有关系吗?

接着上述的例子,我们将Name属性放在最后面再试一试。

    [Serializable]
    public class Person
    {
        [NonSerialized]
        private uint age;
        public uint Age
        {
            get { return age; }
            set { age = value; }
        }

        public UInt16[] Data { get; set; }
        public string Name { get; set; }
    }

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-J2SOlYDZ-1609411109386)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20201231161203021.png)]

好像只有红框中的内容发送了变化,后面的字段字节流的顺序并没有发送变化。所以,字段字节流的顺序不一定与类中字段的顺序一致。

但是这个顺序到底是由什么决定的?俺也不知道。。。。不知道有没有大佬告知一下

五、自定义序列化

具体有什么实际的用处,俺还是不知道。。。

大佬告知一下

六、可以只序列化对象中的字段吗?不需要额外信息

俺目前不知道。但是如果只需要对象中的成员组成的字节流,应该不能使用序列化。
我想到了一些办法。。。见链接

七、Json序列化

点我

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值