我的问题是是否可以确定引用类型的序列化大小(以字节为单位)。
情况如下:
我正在使用 BinaryFormatter 类来序列化基本的 .NET 类型,例如:
[Serializable]
public class Foo
{
public string Foo1 { get; set; }
public string Foo2 { get; set; }
}
我将每个项目序列化为一个 byte[],然后将该段添加到现有 byte[] 的末尾,并在每个段的末尾添加一个回车符以分隔对象。
为了反序列化,我使用 Marshal.ReadByte() 如下:
List<byte> buffer = new List<byte>();
for (int i = 0; i < MapSize; i++)
{
byte b = Marshal.ReadByte(readPtr , i);
if (b != delim) // read until encounter a carriage return
buffer.Add(b);
else
break;
}
readPtr = readPtr + buffer.Count + 1; // incrementing the pointer for the next object
return buffer.ToArray();
我相信使用 Marshal.Copy() 会更有效率,但我需要提前知道序列化字节段的长度。有没有一种方法可以让我从正在序列化的类型中可靠地计算出这个值,或者我可以使用一种整体上更有效的方法?
此外,回车的使用最终也不可靠。所以我想知道是否有更标准的方法来分隔对象,通过自定义我的 BinaryFormatter 或使用其他一些标准化的最佳实践?例如,如果 BinaryFormatter 的序列化是通用的 List<>,是否有一种特定的方式来分隔对象?
最佳答案
没有一种非常好的方法可以预先确定序列化长度。 BinaryFormatter 协议(protocol)的规范可在此处获得: http://msdn.microsoft.com/en-us/library/cc236844(v=prot.10).aspx
为了您的目的,我会为您省去阅读它的麻烦:
- 它被构建为一种可扩展的格式。这允许您稍后添加字段并仍然保持与早期实现的一些兼容性。就您的目的而言,这意味着序列化表格的长度不及时固定。
- 它非常脆弱。二进制格式实际上对其中的字段名称进行了编码。如果您重命名字段,序列化表单的长度将会改变。
- 二进制格式实际上包含序列化编码和对象数据之间的多对一关系。同一个对象可能会以多种不同的方式编码,输出的字节数也不同(我不会解释为什么要这样写)。
如果您想要一种简单的方法来做事,只需创建一个包含所有对象的数组并序列化该单个数组。这可以解决您的大部分问题。分隔不同对象的所有问题都由 BinaryFormatter 处理。你不会有过多的内存复制。最终输出将更加紧凑,因为 BinaryFormatter 每次调用只需指定一次字段名称。
最后,我可以告诉您,额外的内存副本并不是当前实现效率低下的主要原因。 BinaryFormatter 对反射的使用以及它对序列化输出中的字段名称进行编码这一事实使您的效率大大降低。
如果效率是最重要的,那么我建议编写一些自定义代码,以“普通旧数据”格式对结构的内容进行编码。然后您就可以控制写入的内容和方式。
关于c# - 确定 .NET 类型的序列化大小和非托管内存效率,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10148391/