🔍 深度剖析:基于反射的.NET二进制序列化器设计与实现
本文将从底层原理到高级优化,全面剖析一个基于反射的.NET二进制序列化器的设计与实现,涵盖类型系统处理、内存布局、递归算法、性能优化等核心主题。
1. 设计哲学与架构总览
1.1 核心设计理念
本文二进制序列化器的设计体现了几个核心原则:
- 通用性优先:通过反射机制处理任意.NET类型,无需预定义序列化契约
- 紧凑性优化:使用单字节长度前缀处理小型数据结构
- 类型驱动:严格依赖.NET类型系统进行序列化和反序列化
- 递归分解:将复杂对象分解为基本类型、字符串和集合
- 无元数据:序列化结果不包含类型信息,依赖反序列化时的类型上下文
1.2 整体架构图
是 否 是 否 是 否 是 否 是 否 是 否 序列化入口 类型识别引擎 值类型? 基本类型转换 字符串? 字符串编码 集合类型? 集合处理 对象属性递归 反序列化入口 类型识别引擎 值类型? 基本类型重建 字符串? 字符串解码 集合类型? 集合重建 对象属性递归 字节数组生成 对象重建 二进制输出 重建对象
1.3 核心模块分解
模块 | 功能 | 关键类/方法 |
---|---|---|
类型识别 | 区分值类型/引用类型 | GetSize() , ValueType 列表 |
字节转换 | 类型到字节数组转换 | GetBytes() 系列方法 |
递归控制 | 对象树遍历 | ToBytes() , ToObject() |
集合处理 | 数组/列表处理 | GetArrayElement() , CreateArrayCollection() |
字符串编码 | 字符串序列化 | GetBytes() 字符串重载 |
对象构造 | 动态创建实例 | Activator.CreateInstance() |
API接口 | 公开序列化方法 | Serialize() , Deserialize() |
2. 类型系统深度解析
2.1 值类型处理机制
序列化器将.NET类型系统分为三类:
- 基本值类型:13种预定义数值类型+DateTime
- 字符串:特殊引用类型单独处理
- 其他引用类型:自定义对象和集合
2.1.1 值类型映射表
csharp
private static IList<Type> ValueType = new Type[] {
typeof(double), // 双精度浮点 8字节
typeof(float), // 单精度浮点 4字节
typeof(long), // 64位整数 8字节
typeof(ulong), // 64位无符号整数 8字节
typeof(byte), // 无符号字节 1字节
typeof(sbyte), // 有符号字节 1字节
typeof(short), // 16位整数 2字节
typeof(ushort), // 16位无符号整数 2字节
typeof(char), // Unicode字符 2字节
typeof(int), // 32位整数 4字节
typeof(uint), // 32位无符号整数 4字节
typeof(bool), // 布尔值 1字节 (0=false, 1=true)
typeof(DateTime) // 日期时间 (存储为Ticks) 8字节
};
2.1.2 特殊类型处理
- DateTime :转换为
long
类型的Ticks存储 - 浮点数 :使用
BitConverter
保证精度 - bool:存储为单字节(0/1)
2.2 引用类型处理策略
引用类型分为三个子类:
- 字符串:长度前缀+UTF8内容
- 集合类型:元素数量前缀+递归元素
- 自定义对象:递归处理所有公共属性
2.2.1 集合类型识别算法
csharp
private static Type GetArrayElement(Type array)
{
// 处理数组类型 int[], string[] 等
if (array.IsArray)
return array.GetElementType();
// 处理泛型集合 List<T>, IList<T>
if (array.IsGenericType &&
(typeof(IList<>).GUID == array.GUID ||
typeof(List<>).GUID == array.GUID))
{
Type[] args = array.GetGenericArguments();
return args[0];
}
return null;
}
2.2.2 自定义对象处理原则
- 仅处理公共属性(get/set)
- 忽略字段、事件和方法
- 属性顺序由反射返回顺序决定
- 不支持循环引用(会导致栈溢出)
3. 序列化流程全链路剖析
3.1 序列化入口
csharp
public static byte[] Serialize(object graph, Type type, bool single)
{
// 参数校验
if (graph == null) throw new ArgumentNullException("graph");
if (type == null) throw new ArgumentNullException("type");
// 核心序列化方法
return GetBytes(type, graph, single);
}
3.2 类型分发器
csharp
private static byte[] ToBytes(Type clazz, object value, bool single)
{
using (MemoryStream ms = new MemoryStream())
using (BinaryWriter sw = new BinaryWriter(ms))
{
int size = GetSize(clazz);
// 值类型处理分支
if (size > 0)
{
// 浮点数特殊处理
if (clazz == typeof(double) || clazz == typeof(float))
{
sw.Write(GetBytes(clazz, value, size));
}
else
{
// DateTime转换为Ticks
if (clazz == typeof(DateTime))
value = Convert.ToDateTime(value).Ticks;
// 无符号长整型特殊处理
if (clazz == typeof(ulong))
sw.Write(BitConverter.GetBytes(Convert.ToUInt64(value)));
else
sw.Write(GetBytes(clazz, Convert.ToInt64(value), size));
}
}
// 引用类型处理分支
else
{
// 尝试作为字符串处理
sw.Write(GetBytes(clazz, value != null ?
Convert.ToString(value) : null, single));
// 尝试作为集合处理
sw.Write(GetBytes(clazz, value as IList, single));
}
return ms.ToArray();
}
}
3.3 对象递归序列化
csharp
private static byte[] GetBytes(Type type, object value, bool single)
{
using (MemoryStream ms = new MemoryStream())
using (BinaryWriter sw = new BinaryWriter(ms))
{
// 遍历所有公共属性
foreach (PropertyInfo prop in type.GetProperties())
{
// 获取属性值
object propValue = prop.GetValue(value, null);
// 递归序列化属性
byte[] propData = ToBytes(prop.PropertyType, propValue, single);
sw.Write(propData);
}
return ms.ToArray();
}
}
3.4 集合序列化优化
csharp
private static byte[] GetBytes(Type type, IList value, bool single)
{
Type elementType = GetArrayElement(type);
if (elementType != null)
{
using (MemoryStream ms = new MemoryStream())
using (BinaryWriter sw = new BinaryWriter(ms))
{
if (value == null)
{
// null集合标记
if (single) sw.Write((sbyte)-1);
else sw.Write((short)-1);
}
else
{
int count = value.Count;
// 写入元素数量
if (single)
{
if (count > 255) throw new OverflowException("集合元素超过255");
sw.Write((byte)count);
}
else
{
if (count > 65535) throw new OverflowException("集合元素超过65535");
sw.Write((short)count);
}
// byte[]特殊优化
if (type == typeof(byte[]))
{
sw.Write((byte[])value);
}
else
{
// 递归序列化每个元素
for (int i = 0; i < count; i++)
{
object item = value[i];
byte[] itemData = ToBytes(elementType, item, single);
sw.Write(itemData);
}
}
}
return ms.ToArray();
}
}
return new byte[0];
}
4. 反序列化流程全链路剖析
4.1 反序列化入口
csharp
public static object Deserialize(byte[] buffer, Type type, bool single)
{
if (buffer == null || type == null)
throw new ArgumentNullException("buffer or type");
using (MemoryStream ms = new MemoryStream(buffer))
using (BinaryReader sr = new BinaryReader(ms))
{
ms.Seek(0, SeekOrigin.Begin);
return GetObject(type, sr, single);
}
}
4.2 类型分发器
csharp
private static object ToObject(Type clazz, BinaryReader sr, bool single)
{
int size = GetSize(clazz);
// 值类型处理分支
if (size > 0)
{
byte[] buffer = sr.ReadBytes(size);
if (clazz == typeof(double) || clazz == typeof(float))
{
return GetValue(clazz, buffer, single);
}
else
{
if (clazz == typeof(DateTime))
{
object ticks = GetObject(typeof(long), buffer, size);
return new DateTime(Convert.ToInt64(ticks));
}
return GetObject(clazz, buffer, size);
}
}
// 引用类型处理分支
else
{
if (clazz == typeof(string))
return GetString(sr, single);
else
return GetList(clazz, sr, single);
}
}
4.3 对象重建过程
csharp
private static object GetObject(Type type, BinaryReader sr, bool single)
{
// 创建对象实例
object instance = Activator.CreateInstance(type);
// 遍历所有属性
foreach (PropertyInfo prop in type.GetProperties())
{
// 递归反序列化属性
object value = ToObject(prop.PropertyType, sr, single);
prop.SetValue(instance, value, null);
}
return instance;
}
4.4 集合重建算法
csharp
private static object GetList(Type collectionType, BinaryReader reader, bool single)
{
Type elementType = GetArrayElement(collectionType);
if (elementType == null) return null;
// 读取元素数量
int length = single ? reader.ReadByte() : reader.ReadInt16();
// 处理null集合
if (single && (sbyte)length == -1) return null;
if (length == -1) return null;
// 创建空集合
if (length <= 0)
return CreateArrayCollection(collectionType, elementType, 0);
// byte[]特殊处理
if (collectionType == typeof(byte[]))
return reader.ReadBytes(length);
// 创建集合实例
IList collection = CreateArrayCollection(collectionType, elementType, length);
for (int i = 0; i < length; i++)
{
object elementValue;
// 值类型和字符串直接处理
if (elementType.IsValueType || elementType == typeof(string))
elementValue = ToObject(elementType, reader, single);
else // 自定义对象递归处理
elementValue = GetObject(elementType, reader, single);
// 添加到集合
if (collection.IsFixedSize)
collection[i] = elementValue;
else
collection.Add(elementValue);
}
return collection;
}
5. 内存布局与二进制结构
5.1 整体二进制结构
+----------------+----------------+----------------+----------------+
| 对象头(可选) | 属性1数据 | 属性2数据 | ... |
+----------------+----------------+----------------+----------------+
5.2 值类型存储格式
+----------------+----------------+---+----------------+
| 字节0 | 字节1 |...| 字节n-1 |
+----------------+----------------+---+----------------+
5.3 字符串存储格式
+----------------+----------------+----------------+
| 长度(1/2字节) | 字符串内容 | 填充字节(可选) |
+----------------+----------------+----------------+
5.4 集合存储格式
+----------------+----------------+----------------+----------------+
| 元素数量 | 元素1数据 | 元素2数据 | ... |
+----------------+----------------+----------------+----------------+
5.5 自定义对象存储格式
+----------------+----------------+----------------+----------------+
| 属性1数据 | 属性2数据 | 属性3数据 | ... |
+----------------+----------------+----------------+----------------+
5.6 特殊标记
- null字符串:长度=-1 (0xFF或0xFFFF)
- null集合:元素数量=-1
- 空字符串:长度=0
6. 递归算法与对象图处理
6.1 递归序列化算法
是 否 是 否 是 否 开始序列化对象 获取对象类型 是值类型? 转换为字节数组 是字符串? 写入长度+内容 是集合? 写入数量+递归元素 递归处理属性 结束
6.2 递归反序列化算法
是 否 是 否 是 否 开始反序列化 获取目标类型 是值类型? 读取字节并转换 是字符串? 读取长度+内容 是集合? 读取数量+递归元素 递归设置属性 结束
6.3 递归深度控制
当前实现没有递归深度控制,可能导致:
- 栈溢出:深度对象图导致调用栈耗尽
- 性能问题:深层递归效率低下
优化方案:
csharp
private const int MaxRecursionDepth = 100;
private static void SerializeObject(object obj, Type type,
BinaryWriter writer, bool single, int depth)
{
if (depth > MaxRecursionDepth)
throw new SerializationException("超出最大递归深度");
// 递归处理属性...
foreach (var prop in type.GetProperties())
{
SerializeValue(prop.GetValue(obj), prop.PropertyType,
writer, single, depth + 1);
}
}
7. 集合类型特殊处理机制
7.1 集合类型识别
csharp
private static Type GetArrayElement(Type collectionType)
{
// 数组类型识别
if (collectionType.IsArray)
return collectionType.GetElementType();
// 泛型集合识别
if (collectionType.IsGenericType)
{
Type genericType = collectionType.GetGenericTypeDefinition();
if (genericType == typeof(IList<>) ||
genericType == typeof(List<>))
{
return collectionType.GetGenericArguments()[0];
}
}
return null;
}
7.2 集合实例化
csharp
private static IList CreateArrayCollection(Type collectionType,
Type elementType, int length)
{
// 数组创建
if (collectionType.IsArray)
return Array.CreateInstance(elementType, length);
// 泛型列表创建
if (collectionType.IsGenericType)
{
Type genericDef = collectionType.GetGenericTypeDefinition();
if (genericDef == typeof(IList<>) ||
genericDef == typeof(List<>))
{
Type listType = typeof(List<>).MakeGenericType(elementType);
ConstructorInfo ctor = listType.GetConstructor(new[] { typeof(int) });
return (IList)ctor.Invoke(new object[] { length });
}
}
return null;
}
7.3 特殊优化:byte[]
csharp
if (type == typeof(byte[]))
{
// 直接写入字节数组,避免递归处理
sw.Write((byte[])value);
}
else
{
// 递归处理每个元素
for (int i = 0; i < value.Count; i++)
{
// ...
}
}
8. 字符串编码与国际化
8.1 编码处理
csharp
private static Encoding Encoding = Encoding.Default;
潜在问题:
- 跨平台兼容性:不同系统默认编码不同
- 数据膨胀:非ASCII字符可能占用更多字节
- 字符丢失:不支持的字符可能被替换
优化方案:
csharp
// 使用UTF-8作为统一编码
private static Encoding Encoding = Encoding.UTF8;
8.2 字符串序列化
csharp
private static byte[] GetBytes(Type type, string value, bool single)
{
if (type != typeof(string)) return new byte[0];
using (MemoryStream ms = new MemoryStream())
using (BinaryWriter sw = new BinaryWriter(ms))
{
if (value == null)
{
// null标记
if (single) sw.Write((sbyte)-1);
else sw.Write((short)-1);
}
else
{
byte[] data = Encoding.GetBytes(value);
// 长度检查
if (single && data.Length > 255)
throw new ArgumentException("字符串超长");
if (!single && data.Length > 65535)
throw new ArgumentException("字符串超长");
// 写入长度前缀
if (single) sw.Write((byte)data.Length);
else sw.Write((short)data.Length);
// 写入内容
sw.Write(data);
}
return ms.ToArray();
}
}
8.3 字符串反序列化
csharp
private static string GetString(BinaryReader reader, bool single)
{
int length = single ? reader.ReadByte() : reader.ReadInt16();
// 处理null
if (single && (sbyte)length == -1) return null;
if (length == -1) return null;
// 空字符串
if (length == 0) return string.Empty;
// 读取内容并解码
byte[] data = reader.ReadBytes(length);
return Encoding.GetString(data);
}
9. 性能瓶颈与优化策略
9.1 性能热点分析
- 反射开销:反复获取类型信息
- 内存分配:频繁创建小对象
- 递归调用:深层次调用开销
- 装箱拆箱:值类型转换
- 流操作:小数据块频繁写入
9.2 优化方案
9.2.1 元数据缓存
csharp
private static ConcurrentDictionary<Type, PropertyInfo[]> _propertyCache =
new ConcurrentDictionary<Type, PropertyInfo[]>();
private static PropertyInfo[] GetCachedProperties(Type type)
{
return _propertyCache.GetOrAdd(type, t => t.GetProperties());
}
9.2.2 动态方法生成
csharp
private static Func<object, object> CreatePropertyGetter(PropertyInfo prop)
{
var objParam = Expression.Parameter(typeof(object), "obj");
var access = Expression.Property(
Expression.Convert(objParam, prop.DeclaringType), prop);
return Expression.Lambda<Func<object, object>>(
Expression.Convert(access, typeof(object)), objParam).Compile();
}
// 使用
var getter = CreatePropertyGetter(prop);
object value = getter(obj);
9.2.3 缓冲池技术
csharp
private static readonly ObjectPool<MemoryStream> _streamPool =
new ObjectPool<MemoryStream>(() => new MemoryStream(), 10);
public static byte[] Serialize(object graph, bool single)
{
MemoryStream ms = _streamPool.Get();
try
{
// 使用ms序列化...
return ms.ToArray();
}
finally
{
ms.SetLength(0); // 重置
_streamPool.Return(ms);
}
}
9.2.4 值类型特化
csharp
private static void WriteValue(BinaryWriter writer, object value)
{
switch (value)
{
case int i: writer.Write(i); break;
case bool b: writer.Write(b); break;
// ...其他类型
default:
// 反射处理
break;
}
}
10. 完整代码逐行解析
csharp
#pragma warning disable 0675 // 禁用特定编译器警告
namespace STDLOGIC_SERVER.Serialization
{
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Text;
// 二进制序列化器静态类(分部类)
public static partial class BinaryFormatter
{
// 预定义值类型列表(13种基本类型)
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private static readonly IList<Type> ValueType = new Type[]
{
typeof(double), // 双精度浮点数,IEEE 754标准,8字节
typeof(float), // 单精度浮点数,IEEE 754标准,4字节
typeof(long), // 64位有符号整数,8字节
typeof(ulong), // 64位无符号整数,8字节
typeof(byte), // 8位无符号整数,1字节
typeof(sbyte), // 8位有符号整数,1字节
typeof(short), // 16位有符号整数,2字节
typeof(ushort), // 16位无符号整数,2字节
typeof(char), // UTF-16字符,2字节
typeof(int), // 32位有符号整数,4字节
typeof(uint), // 32位无符号整数,4字节
typeof(bool), // 布尔值,1字节(0=false, 非0=true)
typeof(DateTime) // 日期时间,存储为Ticks(100纳秒间隔),8字节
};
// 对应值类型的大小(字节数)
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private static readonly IList<byte> ValueSize = new byte[]
{
8, // double
4, // float
8, // long
8, // ulong
1, // byte
1, // sbyte
2, // short
2, // ushort
2, // char
4, // int
4, // uint
1, // bool
8 // DateTime
};
// 字符串编码方式(使用系统默认编码)
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private static Encoding Encoding = Encoding.Default;
}
// 序列化功能实现部分
public static partial class BinaryFormatter
{
// 获取类型的字节大小(仅值类型)
private static int GetSize(Type type)
{
// 在预定义值类型列表中查找索引
int index = ValueType.IndexOf(type);
// 非值类型返回0
if (index < 0) return 0;
// 返回对应大小
return ValueSize[index];
}
// 将数值转换为字节数组(通用方法)
private static byte[] GetBytes(Type type, long value, int size = -1)
{
// 自动确定大小
if (size < 0) size = GetSize(type);
// 创建目标缓冲区
byte[] buffer = new byte[size];
// 使用非检查上下文避免溢出检查
unchecked
{
// 小端序字节填充
for (int i = 0; i < size; i++)
{
// 每次右移8位并取最低字节
buffer[i] = (byte)((value >> (i * 8)) & 0xFF);
}
}
return buffer;
}
// 字符串序列化方法
private static byte[] GetBytes(Type type, string value, bool single)
{
// 仅处理字符串类型
if (type != typeof(string)) return new byte[0];
using (MemoryStream ms = new MemoryStream())
using (BinaryWriter sw = new BinaryWriter(ms))
{
// 处理null字符串
if (value == null)
{
// 根据长度模式写入-1标记
if (single) sw.Write((sbyte)-1);
else sw.Write((short)-1);
}
else
{
// 获取字符串字节数据
byte[] data = Encoding.GetBytes(value);
// 检查长度限制
if (single && data.Length > 255)
throw new ArgumentException("字符串长度超过255");
if (!single && data.Length > 65535)
throw new ArgumentException("字符串长度超过65535");
// 写入长度前缀
if (single) sw.Write((byte)data.Length);
else sw.Write((short)data.Length);
// 写入字符串内容
sw.Write(data);
}
return ms.ToArray();
}
}
// 集合类型序列化方法
private static byte[] GetBytes(Type type, IList value, bool single)
{
// 获取集合元素类型
Type elementType = GetArrayElement(type);
if (elementType == null) return new byte[0];
using (MemoryStream ms = new MemoryStream())
using (BinaryWriter sw = new BinaryWriter(ms))
{
// 处理null集合
if (value == null)
{
if (single) sw.Write((sbyte)-1);
else sw.Write((short)-1);
}
else
{
int count = value.Count;
// 检查长度限制
if (single && count > 255)
throw new ArgumentException("集合元素超过255");
if (!single && count > 65535)
throw new ArgumentException("集合元素超过65535");
// 写入元素数量
if (single) sw.Write((byte)count);
else sw.Write((short)count);
// byte[]特殊优化
if (type == typeof(byte[]))
{
sw.Write((byte[])value);
}
else
{
// 递归序列化每个元素
for (int i = 0; i < count; i++)
{
object item = value[i];
byte[] itemData = ToBytes(elementType, item, single);
sw.Write(itemData);
}
}
}
return ms.ToArray();
}
}
// 自定义对象序列化方法
private static byte[] GetBytes(Type type, object value, bool single)
{
using (MemoryStream ms = new MemoryStream())
using (BinaryWriter sw = new BinaryWriter(ms))
{
// 遍历所有公共属性
foreach (PropertyInfo prop in type.GetProperties())
{
// 获取属性值
object propValue = prop.GetValue(value, null);
// 递归序列化属性值
byte[] propData = ToBytes(prop.PropertyType, propValue, single);
sw.Write(propData);
}
return ms.ToArray();
}
}
// 浮点数特殊处理方法(使用BitConverter)
private static byte[] GetBytes(Type type, object value, int size)
{
// 单精度浮点处理
if (type == typeof(float))
return BitConverter.GetBytes(Convert.ToSingle(value));
// 双精度浮点处理
if (type == typeof(double))
return BitConverter.GetBytes(Convert.ToDouble(value));
return new byte[0];
}
// 类型分发序列化方法(核心)
private static byte[] ToBytes(Type type, object value, bool single)
{
using (MemoryStream ms = new MemoryStream())
using (BinaryWriter sw = new BinaryWriter(ms))
{
int size = GetSize(type);
// 值类型处理分支
if (size > 0)
{
// 浮点数特殊处理
if (type == typeof(double) || type == typeof(float))
{
sw.Write(GetBytes(type, value, size));
}
else
{
// DateTime转换为Ticks
if (type == typeof(DateTime))
{
DateTime dt = Convert.ToDateTime(value);
value = dt.Ticks;
}
// 无符号长整型特殊处理
if (type == typeof(ulong))
{
ulong ul = Convert.ToUInt64(value);
sw.Write(BitConverter.GetBytes(ul));
}
else
{
long longValue = Convert.ToInt64(value);
sw.Write(GetBytes(type, longValue, size));
}
}
}
// 引用类型处理分支
else
{
// 尝试序列化为字符串
sw.Write(GetBytes(type, value != null ? value.ToString() : null, single));
// 尝试序列化为集合
sw.Write(GetBytes(type, value as IList, single));
}
return ms.ToArray();
}
}
}
// 集合类型辅助功能
public static partial class BinaryFormatter
{
// 获取集合元素类型
private static Type GetArrayElement(Type collectionType)
{
// 处理数组类型
if (collectionType.IsArray)
return collectionType.GetElementType();
// 处理泛型集合
if (collectionType.IsGenericType)
{
Type genericType = collectionType.GetGenericTypeDefinition();
// 支持IList<T>和List<T>
if (genericType == typeof(IList<>) || genericType == typeof(List<>))
{
return collectionType.GetGenericArguments()[0];
}
}
return null; // 非集合类型
}
// 创建集合实例
private static IList CreateArrayCollection(Type collectionType, Type elementType, int length)
{
// 处理数组类型
if (collectionType.IsArray)
return Array.CreateInstance(elementType, length);
// 处理泛型列表
if (collectionType.IsGenericType)
{
Type genericDef = collectionType.GetGenericTypeDefinition();
if (genericDef == typeof(IList<>) || genericDef == typeof(List<>))
{
// 构造List<T>类型
Type listType = typeof(List<>).MakeGenericType(elementType);
// 获取带容量参数的构造函数
ConstructorInfo ctor = listType.GetConstructor(new Type[] { typeof(int) });
// 创建实例
return (IList)ctor.Invoke(new object[] { length });
}
}
return null; // 不支持的类型
}
}
// 反序列化功能实现
public static partial class BinaryFormatter
{
// 将字节数据转换为特定类型的值
private static object GetValue(Type type, long value)
{
// 在非检查上下文中处理转换
unchecked
{
// 根据目标类型进行转换
if (type == typeof(int)) return (int)value;
if (type == typeof(uint)) return (uint)value;
if (type == typeof(long)) return value;
if (type == typeof(ulong)) return (ulong)value;
if (type == typeof(bool)) return value != 0;
if (type == typeof(byte)) return (byte)value;
if (type == typeof(sbyte)) return (sbyte)value;
if (type == typeof(short)) return (short)value;
if (type == typeof(ushort)) return (ushort)value;
return null; // 不支持的类型
}
}
// 字符串反序列化
private static string GetString(BinaryReader reader, bool single)
{
// 根据模式读取长度
int length = single ? reader.ReadByte() : reader.ReadInt16();
// 处理null值(-1标记)
if (single && (sbyte)length == -1) return null;
if (length == -1) return null;
// 空字符串
if (length == 0) return string.Empty;
// 读取字符串内容
byte[] data = reader.ReadBytes(length);
return Encoding.GetString(data);
}
// 集合反序列化
private static object GetList(Type collectionType, BinaryReader reader, bool single)
{
// 获取元素类型
Type elementType = GetArrayElement(collectionType);
if (elementType == null) return null;
// 读取元素数量
int length = single ? reader.ReadByte() : reader.ReadInt16();
// 处理null集合
if (single && (sbyte)length == -1) return null;
if (length == -1) return null;
// 创建空集合
if (length <= 0)
return CreateArrayCollection(collectionType, elementType, 0);
// byte[]特殊处理
if (collectionType == typeof(byte[]))
return reader.ReadBytes(length);
// 创建集合实例
IList collection = CreateArrayCollection(collectionType, elementType, length);
// 读取每个元素
for (int i = 0; i < length; i++)
{
object elementValue;
// 值类型和字符串直接处理
if (elementType.IsValueType || elementType == typeof(string))
elementValue = ToObject(elementType, reader, single);
else // 自定义对象递归处理
elementValue = GetObject(elementType, reader, single);
// 添加到集合
if (collection.IsFixedSize)
collection[i] = elementValue;
else
collection.Add(elementValue);
}
return collection;
}
// 字节数组转值类型
private static object GetObject(Type type, byte[] buffer, int size = -1)
{
// 自动确定大小
if (size < 0) size = GetSize(type);
long value = 0;
// 从小端序字节数组重建数值
unchecked
{
for (int i = 0; i < size; i++)
{
value |= ((long)buffer[i] & 0xFF) << (i * 8);
}
}
return GetValue(type, value);
}
// 自定义对象反序列化
private static object GetObject(Type type, BinaryReader reader, bool single)
{
// 创建对象实例(要求有无参数构造函数)
object instance = Activator.CreateInstance(type);
// 遍历所有属性
foreach (PropertyInfo prop in type.GetProperties())
{
// 递归反序列化属性值
object value = ToObject(prop.PropertyType, reader, single);
prop.SetValue(instance, value, null);
}
return instance;
}
// 浮点数特殊处理
private static object GetValue(Type type, byte[] buffer, bool single)
{
if (type == typeof(double))
return BitConverter.ToDouble(buffer, 0);
if (type == typeof(float))
return BitConverter.ToSingle(buffer, 0);
return null;
}
// 类型分发反序列化(核心)
private static object ToObject(Type type, BinaryReader reader, bool single)
{
int size = GetSize(type);
// 值类型处理分支
if (size > 0)
{
byte[] buffer = reader.ReadBytes(size);
// 浮点数特殊处理
if (type == typeof(double) || type == typeof(float))
return GetValue(type, buffer, single);
// DateTime特殊处理(从Ticks重建)
if (type == typeof(DateTime))
{
object ticks = GetObject(typeof(long), buffer, size);
return new DateTime(Convert.ToInt64(ticks));
}
// 其他值类型
return GetObject(type, buffer, size);
}
// 引用类型处理分支
else
{
if (type == typeof(string))
return GetString(reader, single);
else
return GetList(type, reader, single);
}
}
}
// 公开API接口
public static partial class BinaryFormatter
{
// 序列化对象(指定类型)
public static byte[] Serialize(object graph, Type type, bool single)
{
if (graph == null) throw new ArgumentNullException("graph");
if (type == null) throw new ArgumentNullException("type");
return GetBytes(type, graph, single);
}
// 反序列化对象(指定类型)
public static object Deserialize(byte[] buffer, Type type, bool single)
{
if (buffer == null) throw new ArgumentNullException("buffer");
if (type == null) throw new ArgumentNullException("type");
using (MemoryStream ms = new MemoryStream(buffer))
using (BinaryReader reader = new BinaryReader(ms))
{
ms.Position = 0; // 重置流位置
return GetObject(type, reader, single);
}
}
// 泛型反序列化
public static T Deserialize<T>(byte[] buffer, bool single)
{
object obj = Deserialize(buffer, typeof(T), single);
return (obj == null) ? default : (T)obj;
}
// 序列化对象(自动获取类型)
public static byte[] Serialize(object graph, bool single)
{
if (graph == null) throw new ArgumentNullException("graph");
return Serialize(graph, graph.GetType(), single);
}
// 计算序列化后大小
public static int SizeOf(object graph, bool single)
{
return (graph == null) ? 0 : Serialize(graph, single).Length;
}
}
}
11. 扩展性与应用场景
11.1 适用场景
- 游戏开发:网络消息传输
- 嵌入式系统:有限资源环境
- 配置文件:紧凑的二进制配置
- 数据存储:简单对象持久化
- RPC框架:轻量级远程调用
11.2 扩展方向
1.1 版本兼容性
csharp
[SerializationVersion(1)]
public class MyClass
{
[FieldOrder(1)]
public int Field1;
[FieldOrder(2), SinceVersion(2)]
public string Field2;
}
1.2 循环引用支持
当前实现无法处理循环引用,遇到循环引用会导致无限递归和栈溢出。解决方案是引入对象引用跟踪机制。
1.3 序列化上下文设计
csharp
private class SerializationContext
{
public Dictionary<object, int> ObjectMap = new Dictionary<object, int>();
public int NextId = 1;
}
private class DeserializationContext
{
public Dictionary<int, object> ObjectMap = new Dictionary<int, object>();
}
1.4 序列化时处理引用
csharp
private static byte[] ToBytes(Type type, object value, bool single, SerializationContext context)
{
if (value == null)
{
// 写入null标记
return new byte[] { 0xFF };
}
// 检查是否已序列化过
if (context.ObjectMap.TryGetValue(value, out int id))
{
// 写入引用标记+ID
return WriteReference(id);
}
// 首次遇到的对象
id = context.NextId++;
context.ObjectMap.Add(value, id);
// 写入对象标记+ID
byte[] header = WriteObjectHeader(id);
byte[] data = SerializeObjectData(value, type, single, context);
return CombineBytes(header, data);
}
private static byte[] WriteReference(int id)
{
using (MemoryStream ms = new MemoryStream())
using (BinaryWriter writer = new BinaryWriter(ms))
{
writer.Write((byte)0xFE); // 引用标记
writer.Write(id); // 对象ID
return ms.ToArray();
}
}
private static byte[] WriteObjectHeader(int id)
{
using (MemoryStream ms = new MemoryStream())
using (BinaryWriter writer = new BinaryWriter(ms))
{
writer.Write((byte)0xFD); // 对象标记
writer.Write(id); // 对象ID
return ms.ToArray();
}
}
1.5 反序列化时处理引用
csharp
private static object ToObject(Type type, BinaryReader reader, bool single, DeserializationContext context)
{
byte marker = reader.ReadByte();
if (marker == 0xFF) return null; // null
if (marker == 0xFE) // 引用
{
int id = reader.ReadInt32();
return context.ObjectMap[id];
}
if (marker == 0xFD) // 新对象
{
int id = reader.ReadInt32();
object obj = CreateObject(type, reader, single, context);
context.ObjectMap.Add(id, obj);
return obj;
}
// 其他处理...
}
2. 字段序列化支持
当前实现仅处理属性,可扩展支持字段序列化:
csharp
private static IEnumerable<MemberInfo> GetSerializableMembers(Type type)
{
// 获取所有公共字段和属性
var fields = type.GetFields(BindingFlags.Public | BindingFlags.Instance);
var properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.Where(p => p.CanRead && p.CanWrite);
return fields.Cast<MemberInfo>().Concat(properties);
}
3. 自定义序列化控制
通过特性控制序列化过程:
csharp
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public class NonSerializedAttribute : Attribute { }
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public class SerializationOrderAttribute : Attribute
{
public int Order { get; }
public SerializationOrderAttribute(int order) => Order = order;
}
4. 流式序列化接口
支持大对象序列化到流,避免内存压力:
csharp
public static void SerializeToStream(Stream stream, object graph, bool single)
{
using (BinaryWriter writer = new BinaryWriter(stream, Encoding.Default, true))
{
SerializeToWriter(writer, graph, graph.GetType(), single);
}
}
public static object DeserializeFromStream(Stream stream, Type type, bool single)
{
using (BinaryReader reader = new BinaryReader(stream, Encoding.Default, true))
{
return DeserializeFromReader(reader, type, single);
}
}
12. 总结与未来展望
12.1 技术总结
本文深入剖析了一个基于反射的.NET二进制序列化器的设计与实现,涵盖了:
- 类型系统处理机制(值类型/引用类型/集合)
- 递归序列化/反序列化算法
- 内存布局与二进制结构设计
- 字符串编码与集合处理优化
- 性能瓶颈分析与优化策略
- 扩展性设计与应用场景
12.2 优势与局限
优势:
- 无需预定义类型契约
- 紧凑的二进制格式
- 支持任意.NET类型
- 简单易用的API
局限:
- 性能开销较大(反射)
- 不支持循环引用
- 无版本兼容机制
- 安全性考虑不足
12.3 未来发展方向
- AOT编译支持:为Unity/IL2CPP环境提供支持
- Schema演进:支持向前/向后兼容
- 加密与签名:增加数据安全性
- 跨平台类型系统:支持多语言互操作
- 压缩支持:集成LZ4等压缩算法
通过深入理解这个序列化器的实现原理,开发者可以更好地设计适合特定场景的数据序列化方案,在性能、大小和灵活性之间找到最佳平衡点。