c#中的DRY序列化:抽象、委托或反射
本文关键字:反射 抽象 中的 DRY 序列化 | 更新日期: 2023-09-27 18:10:31
我正在(反)序列化一个网络多人游戏的一些数据结构,对于要(反)序列化的每个数据结构,为了可维护性,我想只定义一次(反)序列化的顺序。
我可以使用c#的抽象类方法来实现我的目标,但是这样做有几个问题:
-
性能:我不希望内置类型
使用ref参数时产生装箱问题。 性能:为每个(反)序列化操作添加额外的抽象方法调用也不理想
额外类型:我必须不必要地初始化我反序列化的所有变量,因为c#不允许我互换传递"ref"answers"out"参数
如何避免重复数据结构(反)序列化的定义,同时避免上述部分或全部问题?
(我尝试过委托和反射,但我最容易想到这个解决方案):
public struct ControllerSnapshot
{
public Vector2 m_lStick;
static private void Op(ref float lStickX, ref float lStickY, Op<float> op)
{
//define (de)serialization order here once and only once
lStickX = op.Invoke(lStickX);
lStickY = op.Invoke(lStickY);
}
public ControllerSnapshot(uLink.BitStream bitStream)
{
OpRead<float> opRead = new OpRead<float>(bitStream);
float lStickX,lStickY;
lStickX = lStickY = 0.0f;//3.can't use "out"; have to match Op's "ref" params
Op(ref lStickX,ref lStickY,opRead);
m_lStick = new Vector2(lStickX,lStickY);
}
public void Serialize(uLink.BitStream bitStream)
{
OpWrite<float> opWrite = new OpWrite<float>(bitStream);
Op(ref m_lStick.x, ref m_lStick.y, opWrite);
}
};
//in order to make the above work this needs to be defined:
abstract class Op<T>
{
public Op(uLink.BitStream bitStream)
{
m_bitStream = bitStream;
}
abstract public T Invoke(T arg);
protected uLink.BitStream m_bitStream;
}
class OpRead<T>:Op<T>
{
public OpRead(uLink.BitStream bitStream) : base(bitStream) { }
override public T Invoke(T arg)
{
return m_bitStream.Read<T>();
}
}
class OpWrite<T>:Op<T>
{
public OpWrite(uLink.BitStream bitStream) : base(bitStream) { }
override public T Invoke(T arg)
{
m_bitStream.Write<T>(arg);
return arg;
}
}
//by contrast, the "obvious" code duplicates the order of (de)serialization, which I
//want to avoid, especially as (de)serialization becomes increasingly complex:
public ControllerSnapshot(uLink.BitStream bitStream)
{
float lStickX,lStickY;
lStickX = bitStream.Read<float>();
lStickY = bitStream.Read<float>();
m_lStick = new Vector2(lStickX,lStickY);
}
public void Serialize(uLink.BitStream bitStream)
{
bitStream.Write<float>(m_lStick.x);
bitStream.Write<float>(m_lStick.y);
}
首先,我不认为虚拟方法调用在这里会产生任何不同——您正在序列化您的对象以便通过网络传输。额外的几纳秒是没有意义的。
你提出的解决方案也让你重复自己——你仍然必须在序列化和反序列化中指定你的属性。
唯一可以避免这种情况的方法是通过某种方式指定哪些字段应该序列化,并使用某种反射——就像。net的序列化器十年来一直在做的那样。
更新:实际上,为什么不使用Google的Protobufs呢?