我正在编写一些将用于与C#TCP服务器通信的类,我正在使用BinaryWriter
和BinaryReader
编写序列化/反序列化方法。这很容易,但我遇到的情况是我有一个类Class1,里面包含一个实例Class2。这两个类都实现了一个定义方法byte[] ToBytes()
和void FromBytes(byte[] data)
的接口。所以我有这个代码:
public class Class1
{
public int Action;
public Class2 Data;
public void FromBytes(byte[] data)
{
BinaryReader br = new BinaryReader(new MemoryStream(data));
Action= br.ReadInt32();
Data = new Class2();
Data.FromBytes(br.ReadBytes(___));
br.Close();
}
}
问题是,ReadBytes
电话会怎样?除了硬编码实现此接口的任何对象的大小之外,我不确定是否可以这样做,但是有更优雅的东西吗?我考虑过使用反射来计算它在运行时(为未来的调用缓存它),但这看起来更加丑陋。
编辑:我应该指出,如果数据是可变长度的,那么二进制表示包括必要的数据长度,并且解串器将处理它。
答案 0 :(得分:2)
也许将实例的大小放在实例数据的开头?虽然,如果您使用BinaryReader
,您应该能够将阅读器本身传递给Class2
对象中的方法,并且可以使用它来反序列化二进制数据。
答案 1 :(得分:2)
通常情况下,我会传递byte[]
(可能是约束流,以阻止它在我们预期的区域之外读取)或包装阅读器,而不是传递Stream
,并使用它 - 即让课程阅读所需内容。
另一个简单的选择是在序列化期间对数据进行长度前缀,以便您事先知道大小。
或者,节省了很多麻烦并使用预先滚动的二进制序列化框架。有几个......他们都必须解决这个问题。很高兴(这是我的宠物区)。
我也担心你班上的问题分离,但这是一个副作用。
答案 2 :(得分:2)
如果我正确理解了您的问题,并且没有说明您解决此问题的方法的正确性, Marshal.SizeOf
应该可以解决您的问题。
我冒昧地填写了代码中的空白:
class Program
{
[StructLayout(LayoutKind.Sequential)]
public class Class2
{
public int Data;
public int SomeMoreData;
internal void FromBytes(byte[] p)
{
BinaryReader br = new BinaryReader(new MemoryStream(p));
Data = br.ReadInt32();
SomeMoreData = br.ReadInt32();
br.Close();
}
}
public class Class1
{
public int Action;
public Class2 Data;
public void FromBytes(byte[] data)
{
BinaryReader br = new BinaryReader(new MemoryStream(data));
Action = br.ReadInt32();
Data = new Class2();
int sizeOfClass2Instance = Marshal.SizeOf(Data);
Data.FromBytes(br.ReadBytes(sizeOfClass2Instance));
br.Close();
}
}
static void Main(string[] args)
{
Class1 c1 = new Class1();
int[] data = new int[3] { 1, 2, 3 };
byte[] dataInBytes = new byte[data.Length * sizeof(int)];
for (int i=0;i<data.Length;i++)
{
byte[] src = BitConverter.GetBytes(data[i]);
Array.Copy(src, 0, dataInBytes, i * sizeof(int), sizeof(int));
}
c1.FromBytes(dataInBytes);
}
}
诀窍是,Marshal.SizeOf依赖于你的类的StructLayout属性。您必须明确说明数据在类中的存储方式。
答案 3 :(得分:1)
如果您确定Class2的每个对象在使用ToBytes时都提供相同数量的字节,请创建Class2的虚拟对象并使用ToBytes()。Length。
或者只是:
Data = new Class2();
Data.FromBytes(br.ReadBytes(Data.ToBytes().Length));
(显然,你可以通过存储Data.ToBytes()。长度在某处并重复使用来提高效率。)