细说C#中的系列化与反连串化的基本原理和经过

就算大家平时都应用第叁方库来开始展览种类化和反种类化,用起来也很便利,但起码得知道系列化与反连串化的基本原理。

精晓人就别看了!

专注:从.NET Framework 2.0
初始,类别化格式化器类SoapFormatter已不合时宜。请改用 BinaryFormatter。

  • 连串化:把对象对象转换为字节流的长河
  • 反系列化:把字节流转换回对象的经过

种类化与反种类化需求1个连串化器类:即System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
实例化1个格式化器BinaryFormatter类:BinaryFormatter binaryFormatter = new BinaryFormatter();

一、序列化:

binaryFormatter.Serialize(Stream stream, Object obj);

  • 该办法把3个或八个对象对象连串化为字节流并保存到目的流对象stream中。须要提供二个目的流对象stream(stream对象能够是基类Stream的派生类:FileStream、MemoryStream、NetWorkStream等流对象);

类别化进度:

  • 体系化时,首先判断各样对象的类型定义是或不是选用了可体系化[Serializable]特点,不然抛出相当。
  • 说不上调用对象中这一个被标记了[OnSerializing]特色的兼具办法。(即:执行体系化前,先调用该方法做1些工作)
  • 接下去,利用反射机制来取得每一个指标对象的项目中保有必要类别化的实例字段的新闻,并读取对应字段的值保存到字节流中。
  • 体系化时,还保留了目的项目标人名、定义类型程序集的姓名,作为标识消息保存到流中(用于反连串化)。
  • 终极,调用全部被标记了[OnSerialized]个性的法子。(即:种类化实现后,调用该情势做一些业务)

二、反种类化:

SomeObject obj = (SomeObject)binaryFormatter.Deserialize(Stream stream);

  • 该方法把指标流对象stream中的字节流反种类化为Object对象,可遵照须要实行转型为相应的靶子对象

反连串化进度:

  • 反体系化时,首先从字节流中读取程序集的标识音信,然后调用System.Reflection.Assembly类的Load()艺术加载该程序集到当下的AppDomain中,唯有当程序集加载成功后,格式化器才能在程序集中查找是不是留存与特殊需求被反种类化的目的的类型音讯相同的门类
  • 找到类型后,调用对象中那个被标记了[OnDeserializing]本性的装有办法
  • 接下去利用该类型创设实例
  • 然后从字节流中收获对应字段的值对该实例实行开头化。
  • 最终,调用全部被标记了[OnDeserialized]特征的章程。

此进程中若找不到非凡的花色,则会抛出至极终止反连串化。但是,小编在动用第壹方类库反连串化JSON文件时,JSON文件并不设有对象名和程序集名的标识音讯,第1方类库的格式化器应该是基于各种对象的成员名称、类型,在当前AppDomain中的全部程序集中开始展览检索相称的档次。

注意:

  • Infiniti把连串化或反连串化的历程放进try块中,用catch
    (SerializationException
    e)块拍卖要求处理的越发,并在finally块中放出能源(关闭流)。
  • 能够把流的概念放在using语句的“()”中,把系列化反体系化代码放在using块内,来达成机关释放能源的指标。

叁、种类化配置

在实施类别化和反类别化在此之前,可以对格式化器的Context天性实行安装,Context品质是3个StreamingContext结构
binaryFormatter.Context = new StreamingContext(StreamingContextStates.Remoting);//内定为来源和目标地是长距离的

StreamingContext结构的性质有七个:

  • State质量,是3个枚举类型StreamingContextStates的值,用来证实连串化和反种类化的对象的起点和指标地
  • Context品质,3个上下文对象的引用,蕴含了用户期望收获的别的上下文新闻

StreamingContext结构存在的意思就是经过State品质的值描述给定的行列化流的源和指标,并接纳Context质量提供一个由调用方定义的附加上下文。
(因为同贰个被系列化好的指标只怕会有例外的指标地,如分裂机器,差异进度个中,大家就能够透过State属性的气象来标识对象的目标地)

演示:利用体系化和反体系化,定义三个纵深克隆3个对象的诀要

    public object DeepCloneObject(object oldObj)
    {
        try
        {
            using (MemoryStream stream = new MemoryStream())
            {
                BinaryFormatter bf = new BinaryFormatter();
                bf.Context = new StreamingContext(StreamingContextStates.Clone);
                //把对象序列化到流中
                bf.Serialize(stream, oldObj);
                //在进行反序列化前,需要先定位到内存流的起始位置
                stream.Position = 0;
                //将内存流中的内容反序列化成新的对象
                return bf.Deserialize(stream);
            }
        }
        catch(SerializationException e)
        {
            Console.WriteLine("序列化和反序列化时出错了,错误信息为:" + e.Message);
            //不做处理,重新抛出原异常对象
            throw;
        }
        finally
        {
            //using中的stream对象会被自动释放,这里不要对它处理
        }
    }

四、如果某些项目标分子不可能进行系列化或反系列化,则足以为该品种达成接口ISerializationCallbackReceiver,该接口定义了五个章程:

比如说在Unity3d中,不能够系列化枚举类型的积极分子,就供给把她标记为[NonSerialized]不对她处理,然后定义一个该成员的字符串格局的积极分子,通过该字符串和对应枚举类型的转换,就能够高达连串化的指标了。如下代码:

public enum ItemType
{
    left,
    right
}

public class ScoreModel:ISerializationCallbackReceiver
{
    public int Score { get; set; }

    [NonSerialized]
    public ItemType itemType;
    public string itemTypeString;

    //反序列化完成自动后调用
    public void OnAfterDeserialize()
    {
        itemType = (ItemType)Enum.Parse(typeof(ItemType), itemTypeString);
    }
    //进行序列化之前自动调用
    public void OnBeforeSerialize()
    {
        itemTypeString = itemType.ToString();
    }
}

5、关于类别化为派生类类型的气象

不畏是第二方类库,恐怕也无力回天处理那种情形,比如:从JSON中反种类化后得到的目的的分子是三个基类类型的,假诺直白把该成员强转为我们其实供给的子类类型,平常情况下是11分的,那时就须要自定义一些艺术来完毕了,利用协变在系列化进程中回到子类类型的对象给基类类型,那样获得的基类类型就足以强转为子类类型了。具体落到实处代码,大家能够搜起来!

相关文章