我正在构建一个系统,用于将类序列化为字符串并通过网络发送给我作为实习的教育游戏。它就像一个魅力。但突然间我注意到自己在看着我的代码,想知道" 这是怎么回事?"。
我正在谈论的课程被粘贴在下面而没有所有不必要的部分。
[Serializable]
public class Question : ISerializable
{
public readonly int id;
// Some more
// variables
// Default Constructor
public Question (int id /*, some more parameters*/)
{
this.id = id;
// Some initialization code
}
// Pay attention to this Constructor
public Question (SerializationInfo info, StreamingContext context)
{
id = (int)info.GetValue ("id", typeof (int));
// Some deserialization code
}
// Serialization overload method
public void GetObjectData (SerializationInfo info, StreamingContext context)
{
info.AddValue ("id", id, typeof (int));
// Some serialization code
}
// Serialization method actually used
static public string SerializeToString (Question p)
{
BinaryFormatter bf = new BinaryFormatter ();
using (MemoryStream ms = new MemoryStream ())
{
bf.Serialize (ms, p);
return Convert.ToBase64String (ms.ToArray ());
}
}
// This is where I'm going crazy
static public Question DeserializeFromString (string serialized)
{
BinaryFormatter bf = new BinaryFormatter ();
using (MemoryStream ms = new MemoryStream (Convert.FromBase64String (serialized)))
{
return (Question)bf.Deserialize (ms);
}
}
}
如果我在服务器端执行此操作:
// ...
string serialized = Question.SerializeToString (actualQuestion);
// Send "serialized" through the network
// ...
这在客户端:
// ...
// Receive a string
Question receivedQuestion = Question.DeserializeFromString (receivedString);
// ...
有效!但为什么呢?
我想知道的是DeserializeFromString的return语句中引人注目的内容。
return (Question)bf.Deserialize (ms);
这是我真正理解的: bf.Deserialize(ms)接收使用序列化字符串填充的内存流,并返回反序列化数据的Object。
我想了解在低级别(或至少在编译器和运行时级别)发生的事情,如果可能的话,还要了解内存中发生的事情。
答案 0 :(得分:3)
它不知道序列化了哪个类
知道,BinaryFormatter包含流中序列化对象的类型信息。它记录程序集显示名称,程序集版本,程序集的公钥标记,命名空间名称和类型名称。对于类中的每个字段,它记录字段名称和字段类型,与对象类型的操作方式相同。
请注意,这往往会使二进制序列化变得有点危险,反序列化数据的代码需要能够找回 exact 相同的程序集。几年后趋于困难。
通过序列化到FileStream获得更多洞察力,使用十六进制查看器查看数据。您很快就会看到额外的元数据。
为什么(问题)someObjectOfTypeObject正在调用特殊的构造函数
因为你继承了ISerializable。 BinaryFormatter检查您是否实现了该接口,然后自动寻找带有SerializationInfo和StreamingContext参数的构造函数。
更有趣的情况是不实现ISerializable。 BinaryFormatter然后拉出一个你不能自己拉开的特技,它创建一个对象,而不用调用构造函数。它在CLR中使用后门来执行此操作。设置字段值然后在最初序列化时将对象重建为存储在内存中的方式。