细说C#中之序列化与反序列化的基本原理和进程

尽管如此咱平素还使用第三正在库来进行序列化和倒序列化,用起吧格外便利,但起码得亮序列化与反序列化的基本原理。

解人尽管成形看了!

只顾:从.NET Framework 2.0
开始,序列化格式化器类SoapFormatter已不合时宜。请改用 BinaryFormatter。

  • 序列化:把对象对象转换为字节流的历程
  • 反序列化:把字节约流转换回对象的过程

序列化与反序列化需要一个序列化器类:即System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
实例化一个格式化器BinaryFormatter类:BinaryFormatter binaryFormatter = new BinaryFormatter();

一、序列化:

binaryFormatter.Serialize(Stream stream, Object obj);

  • 拖欠方式把一个或者多个目标靶序列化为字节约流并保存至目标流对象stream中。需要提供一个目标流对象stream(stream对象可以是基类Stream的派生类:FileStream、MemoryStream、NetWorkStream当流动对象);

序列化过程:

  • 序列化时,首先判断每个对象的类型定义是否采用了但序列化[Serializable]特性,否则抛出异常。
  • 副调用对象吃那些被标记了[OnSerializing]特点的有术。(即:执行序列化前,先调整用该法做有事情)
  • 紧接下,利用反射机制来取得每个目标靶的项目中拥有需要序列化的实例字段的消息,并读取对许字段的价值保存到字节流中。
  • 序列化时,还保留了对象项目的姓名、定义类型程序集的全名,作为标识信息保存及流中(用于反序列化)。
  • 最后,调用所有受记了[OnSerialized]特点的措施。(即:序列化完成后,调用该法做有作业)

次、反序列化:

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

  • 拖欠方法将目标流对象stream中之许节约流反序列化为Object对象,可因要求开展转型也对应之对象对象

反序列化过程:

  • 反序列化时,首先由字节流中读取程序集的标识信息,然后调用System.Reflection.Assembly类的Load()艺术加载该次集至即之AppDomain遭受,只有当次集加载成功后,格式化器才会以次集中找是否在和需要让反序列化的对象的类型信息相同之类型
  • 找到类型后,调用对象中那些受记了[OnDeserializing]特征的富有办法
  • 通下利用该项目创建实例
  • 然后起字节流中拿走对许字段的价值对该实例进行初始化。
  • 终极,调用所有为记了[OnDeserialized]特性的章程。

这个过程被设找不顶相当的品类,则会丢来异常终止反序列化。但是,我在使用第三正在类库反序列化JSON文件时,JSON文件并无设有对象名及顺序集名的标识信息,第三方类库的格式化器应该是依据各个对象的分子称、类型,在此时此刻AppDomain遭逢的有所程序集中进行检索匹配的路。

注意:

  • 最好把序列化或反序列化的进程放上try块中,用catch
    (SerializationException
    e)块拍卖得处理的雅,并在finally块中释放资源(关闭流)。
  • 得把流的定义在using语句的“()”中,把序列化反序列化代码放在using片内,来达到机关释放资源的目的。

其三、序列化配置

在履序列化和倒序列化之前,可以对格式化器的Context特性进行安装,Context特性是一个StreamingContext结构
binaryFormatter.Context = new StreamingContext(StreamingContextStates.Remoting);//指定为自及目的地是长途的

StreamingContext布局的性有点儿单:

  • State特性,是一个枚举类型StreamingContextStates的值,用来验证序列化和倒序列化的对象的源于以及目的地
  • Context特性,一个上下文对象的援,包含了用户愿意获得的其余上下文信息

StreamingContext组织是的含义就是经State特性之价值描述给定的阵化流的源与对象,并下Context性提供一个是因为调用方定义的附加上下文。
(因为与一个于序列化好的靶子可能会见生出两样之目的地,如不同机器,不同进程中,我们就好透过State属性的状态来标识对象的目的地)

以身作则:利用序列化和倒序列化,定义一个纵深克隆一个靶的艺术

    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();
    }
}

五、关于序列化为派生类类型的情状

虽是第三正值类库,可能啊无能为力处理这种气象,比如:从JSON中倒序列化后拿走的目标的分子是一个基类类型的,如果直白拿该成员强转为我们实在用的子类类型,正常状况下是大的,这时便得打定义有方法来促成了,利用协变在序列化过程中回到子类类型的靶子吃基类类型,这样得到的基类类型就得胜似转为子类类型了。具体贯彻代码,大家好搜起来!

相关文章