初学者,自用笔记
职责抽象
接口
// 基础序列化接口(所有序列化器的核心契约)
// 定义对象二进制的基础转换能力,适配任意序列化格式
// 全量序列化接口:只提供最基础对象和字节转换
public interface IFullSerializer
{
byte[] Serialize<T>(T obj) where T : class, new();
T Deserialize<T>(byte[] data) where T : class, new();
}
// 增量序列化扩展接口(可选实现,适配需要增量更新的场景)
// 定义增量更新的序列化能力,独立于基础序列化
public interface IDeltaSerializer : IFullSerializer
{
// 增量序列化(对比新旧对象,生成仅包含变更的二进制补丁)
byte[] SerializeDelta<T>(T oldObj, T newObj) where T : class, new();
// 增量反序列化(将增量补丁应用到旧对象,生成新对象)
T ApplyDelta<T>(T oldObj, byte[] deltaData) where T : class, new();
}
// 引用管理扩展接口(可选实现,适配需要处理对象引用的场景)
// 定义对象引用的序列化/反序列化能力,避免重复传输
public interface IReferenceSerializer : IFullSerializer
{
// 设置引用池(序列化前初始化,存储已序列化的对象ID和数据)
void SetReferencePool(Dictionary<ulong, byte[]> refPool);
// 获取引用池(反序列化后获取,用于解析引用关系)
Dictionary<ulong, byte[]> GetReferencePool();
}
// 完整序列化接口:全量 + 增量 + 引用池
public interface ISerializer : IFullSerializer
{
byte[] SerializeDelta<T>(T oldObj, T newObj) where T : class, new();
T ApplyDelta<T>(T oldObj, byte[] deltaData) where T : class, new();
void SetReferencePool(Dictionary<ulong, byte[]> refPool);
Dictionary<ulong, byte[]> GetReferencePool();
}
基类
// 序列化器基类(封装通用逻辑,减少子类重复代码)
public abstract class SerializerBase : IFullSerializer
{
// 通用空值校验(所有序列化器复用)
protected virtual void ValidateInput<T>(T obj) where T : class, new()
{
if (obj == null)
{
throw new ArgumentNullException(nameof(obj), "待序列化对象不能为空");
}
}
// 通用二进制数据校验(所有序列化器复用)
protected virtual void ValidateData(byte[] data)
{
if (data == null || data.Length == 0)
{
throw new ArgumentException("反序列化数据不能为空或空数组", nameof(data));
}
}
// 抽象全量序列化(子类实现具体格式逻辑)
public abstract byte[] Serialize<T>(T obj) where T : class, new();
// 抽象全量反序列化(子类实现具体格式逻辑)
public abstract T Deserialize<T>(byte[] data) where T : class, new();
}
具体实现
// Protobuf序列化器(实现增量+引用能力,适配核心诉求)
public class ProtobufSerializer : SerializerBase, ISerializer
{
// 引用池(存储对象ID与序列化数据的映射,避免重复传输)
private Dictionary<ulong, byte[]> _refPool = new Dictionary<ulong, byte[]>();
// 设置引用池(实现IReferenceSerializer)
public void SetReferencePool(Dictionary<ulong, byte[]> refPool)
{
_refPool = refPool ?? new Dictionary<ulong, byte[]>();
}
// 获取引用池(实现IReferenceSerializer)
public Dictionary<ulong, byte[]> GetReferencePool()
{
return _refPool;
}
// Protobuf全量序列化(紧凑编码+引用处理)
public override byte[] Serialize<T>(T obj) where T : class, new()
{
ValidateInput(obj);
_refPool.Clear(); // 每次序列化重置引用池
// 处理Protobuf消息对象(需继承IMessage)
if (obj is IMessage message)
{
using (var ms = new MemoryStream())
{
// 引用处理:检查对象是否有唯一ID(IHasObjectId为自定义标记接口)
if (obj is IHasObjectId refObj && _refPool.ContainsKey(refObj.ObjectId))
{
// 仅序列化引用标记+ID(紧凑格式)
var refData = new RefObject { IsRef = true, RefId = refObj.ObjectId };
refData.WriteTo(ms);
return ms.ToArray();
}
// 无引用:序列化完整数据并加入引用池
if (obj is IHasObjectId newRefObj)
{
_refPool[newRefObj.ObjectId] = message.ToByteArray();
}
message.WriteTo(ms);
return ms.ToArray();
}
}
return Array.Empty<byte>();
}
// Protobuf全量反序列化
public override T Deserialize<T>(byte[] data) where T : class, new()
{
ValidateData(data);
// 先检查是否为引用数据
var refData = new RefObject();
using (var ms = new MemoryStream(data))
{
refData.MergeFrom(ms);
if (refData.IsRef && _refPool.TryGetValue(refData.RefId, out var rawData))
{
return Deserialize<T>(rawData); // 解析引用对应的原始数据
}
}
// 解析原始数据
if (Activator.CreateInstance<T>() is IMessage message)
{
message.MergeFrom(data);
return message as T;
}
return new T();
}
// Protobuf增量序列化(仅传输变更字段)
public byte[] SerializeDelta<T>(T oldObj, T newObj) where T : class, new()
{
ValidateInput(oldObj);
ValidateInput(newObj);
// 生成变更字段掩码(FieldMask为Protobuf原生类型)
var fieldMask = GenerateFieldMask(oldObj, newObj);
// 构建增量包(仅包含变更字段+元信息)
var deltaPackage = new DeltaPackage
{
Meta = GetMetaData(newObj),
ChangedFields = fieldMask,
Payload = SerializeChangedFields(newObj, fieldMask)
};
return Serialize(deltaPackage);
}
// 增量反序列化(应用补丁到旧对象)
public T ApplyDelta<T>(T oldObj, byte[] deltaData) where T : class, new()
{
ValidateInput(oldObj);
ValidateData(deltaData);
// 反序列化增量包
var deltaPackage = Deserialize<DeltaPackage>(deltaData);
if (deltaPackage == null) return oldObj;
// 应用变更字段到旧对象
ApplyChangedFields(oldObj, deltaPackage.ChangedFields, deltaPackage.Payload);
// 更新版本号(增量更新标记)
if (oldObj is IHasVersion versionObj)
{
versionObj.Version = deltaPackage.Meta.Version;
}
return oldObj;
}
// 辅助:生成变更字段掩码
private FieldMask GenerateFieldMask<T>(T oldObj, T newObj) where T : class, new()
{
var fieldMask = new FieldMask();
var properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (var prop in properties)
{
var oldValue = prop.GetValue(oldObj);
var newValue = prop.GetValue(newObj);
if (!Equals(oldValue, newValue))
{
fieldMask.Paths.Add(prop.Name);
}
}
return fieldMask;
}
// 辅助:仅序列化变更字段
private byte[] SerializeChangedFields<T>(T obj, FieldMask fieldMask) where T : class, new()
{
var partialObj = Activator.CreateInstance<T>();
foreach (var path in fieldMask.Paths)
{
var prop = typeof(T).GetProperty(path);
if (prop != null)
{
prop.SetValue(partialObj, prop.GetValue(obj));
}
}
return Serialize(partialObj);
}
// 辅助:应用变更字段到旧对象
private void ApplyChangedFields<T>(T oldObj, FieldMask fieldMask, byte[] payload) where T : class, new()
{
var partialObj = Deserialize<T>(payload);
foreach (var path in fieldMask.Paths)
{
var prop = typeof(T).GetProperty(path);
if (prop != null)
{
prop.SetValue(oldObj, prop.GetValue(partialObj));
}
}
}
// 辅助:获取对象元信息(版本+ID)
private MetaData GetMetaData<T>(T obj) where T : class, new()
{
var meta = new MetaData();
if (obj is IHasObjectId refObj) meta.ObjectId = refObj.ObjectId;
if (obj is IHasVersion versionObj) meta.Version = versionObj.Version;
return meta;
}
}
简单实例
public class SocketServerDemo : MonoBehaviour
{
// 序列化器配置(仅需修改枚举即可切换格式)
private readonly SerializerType _serializerType = SerializerType.Protobuf;
// 序列化器实例(依赖抽象而非具体实现)
private readonly ISerializer _serializer = SerializerFactory.CreateDeltaSerializer(SerializerType.Protobuf);
// 客户端数据缓存(用于增量对比)
private Dictionary<EndPoint, UserData> _clientDataCache = new Dictionary<EndPoint, UserData>();
private void OnReceiveBody(byte[] body, EndPoint clientEP)
{
// 1. 从缓存获取旧对象
if (!_clientDataCache.TryGetValue(clientEP, out var oldData))
{
oldData = new UserData();
_clientDataCache[clientEP] = oldData;
}
// 2. 增量反序列化(业务层仅依赖IDeltaSerializer抽象)
var newData = _serializer.ApplyDelta(oldData, body);
// 3. 业务处理(更新缓存)
_clientDataCache[clientEP] = newData;
if (newData is IHasVersion versionObj) versionObj.Version++;
// 4. 增量序列化响应(仅传输变更)
var replyData = _serializer.SerializeDelta(oldData, newData);
_server.Send(clientEP, replyData);
}
}
存档系统(待实现)

京公网安备 11010502036488号