1.引入:思考 Instantiate如何实现
Unity中如何真正去克隆一个游戏对象(即如何深拷贝一个游戏对象)
2.序列化和反序列化
思考序列化和反序列化的过程:可以通过序列化将一个对象保存为一个二进制文件以永久保存。同时,还可以将二进制文件反序列化成为一个和被反序列化的对象一样的新的游戏对象。(序列化和反序列化也是深拷贝对象的一种实现方法)。
public static object Instantiate(Object orginal);
Instantiate实现机制便是对象的序列化和反序列化:
先将参数origin所引用的游戏对象序列化,得到了经过序列化之后的序列化流后,再使用反序列化机制将这个序列化流反序列化生成一个新的游戏对象。
3.序列化与反序列化的过程
FormatterSevervice类
序列化
序列化第一步
获取对象的成员类型信息(即MemberInfo数组)
(感觉与反射里面的方法类似,根据Type类型获取可被序列化字段对应类型信息数组)
// 参数:type:表示正在序列化或克隆的类型,context表示发生序列化对象的上下文
// 返回值:MemberInfo[] 可被序列化字段对应类型信息数组
public static MemberInfo[] GetSerializableMembers(Type type)
public static MemberInfo[] GetSerializableMembers(Type type, StreamingContext context)
序列化第二步
前面已经获取到了需要序列化对象的成员类型信息对应的MemberInfo数组,这一步则是要获取其所对应的值数组(一个Object数组)
public static Object[] GetObjectData(Object obj, MemberInfo[] members)
序列化第三步
前面两个步骤已经获取了对象的成员和其对应的值,接下来就需要将这些信息写入流中。
因此这一步先将程序集标识,以及类型的完整名称写入流。
序列化第四步
将程序集标识以及类型的完整名称写入流中之后,格式化器接下来会遍历在第一步和第二部两个数组获得对应名称和对应的值,写入流中。
反序列化
反序列化第一步
与序列化第四步对应,从流中读取程序集标识和完整的类型名称(需要该程序集已经加载到AppDomain中,如果没有被加载,则会抛出异常后终止)
public static Type GetTypeFromAssembly(Assembly asssem, string name)
经过上面调用,格式化器便获得了对象的类型
反序列化第二步
获取到了对象的类型,接下来则是要分别为对象分配内存空间。
public static Object GetUninitializedObject(Type type)
需要注意的是,此时并没有调用构造函数,且对象的所有字节都是被初始化为null或是0
反序列化第三步
分配好内存空间之后,接下来就是要获取序列化中保存的对象的信息了。
首先是要获取成员字段类型信息数组,通过调用GetSerializableMembers方法来构造一个新的MemberInfo数组 ,获得一个已经序列好,现在等待被反序列化的一组字段。
反序列化第四步
接下来自然是获取MemberInfo数组对应的Object数组(值信息)。
因此这一步中,格式化器会根据流中包含的数据创建一个Object数组,并对其进行初始化
到了这一步,便获取到了对应的字段信息以及与字段对应的数值信息,一个新分配的对象。
反序列化第五步
根据字段与字段对应的值为新分配的对象进行初始化。
public static Object PopulateObjectMembers(Object obj, MemberInfo[] members, Object[] data)
通过上面的调用,该方法内部会遍历数组将对象的每个字段和属性初始化为对应的值。