使用反射对任意对象进行二进制序列化的程序
背景
进行网络通信时,或者希望本地存储文件加密时,可以用二进制序列化。序列化时要把类的基本类型字段一个个序列化,遇到成员类要把成员类的基本类型成员也序列化。这样每个类都要有一个专门的序列化程序,这是令人难以接受的。需要封装一些代码,有不同的封装方案。
- 把各种基本数据类型的序列化封装成函数,把一个类序列化时按字段的顺序和类型手动调用这些函数。不过除了字符串麻烦点,其他类型序列化都只要一行;
- 写一个接收object的函数,使用GetFields()得到每个字段的类型,按类型序列化;
还面临的问题是:
- 结果字节数组的长度是由所有字段的个数和类型决定的。需要对每个字段判断类型、对字符串确定长度后才能知道结果字节数组的长度。不可能预先知道结果字节数组的长度。
想到列表可以改变长度,可以先声明一个byte列表,把字段序列化后加到列表后面,全部加完后变成数组。
public class MyBinSerDes
{static MyBinSerDes instance = new MyBinSerDes();public static MyBinSerDes Instance => instance;public byte[] ToBytes(object data){Type dataType = data.GetType();FieldInfo[] fieldInfos = dataType.GetFields();List<byte> byteList = new List<byte>();for (int i = 0; i < fieldInfos.Length; i++){byte[] bytes;object field=fieldInfos[i].GetValue(data);if (field.GetType() == typeof(string)){string str = field as string;byte[] strBytes = Encoding.UTF8.GetBytes(str);bytes = new byte[sizeof(int) + strBytes.Length];BitConverter.GetBytes(strBytes.Length).CopyTo(bytes, 0);strBytes.CopyTo(bytes, sizeof(int));}else if (field.GetType() == typeof(int)){bytes = BitConverter.GetBytes((int)field);}else if (field.GetType() == typeof(float)){bytes = BitConverter.GetBytes((float)field);}else if (field.GetType() == typeof(bool)){bytes = BitConverter.GetBytes((bool)field);}else{#if UNITY_EDITORDebug.Log("字段类型不支持!");#endifbytes = null;}byteList.AddRange(bytes.ToList());}return byteList.ToArray();}
}