为什么要调用构造函数而不是给我一个错误?

时间:2015-08-05 20:57:33

标签: c# .net serialization

我正在构建一个系统,用于将类序列化为字符串并通过网络发送给我作为实习的教育游戏。它就像一个魅力。但突然间我注意到自己在看着我的代码,想知道" 这是怎么回事?"。

我正在谈论的课程被粘贴在下面而没有所有不必要的部分。

[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。

  1. 变量如何存储在Object中,因为它不知道它的原型? (它不知道序列化了哪个类)
  2. 为什么(问题)someObjectOfTypeObject正在调用特殊的构造函数而不是搜索显式转换的重载,或者是一个接收Object的构造函数(并且在这些搜索中失败,因为我没有实现它们) ?
  3. 我想了解在低级别(或至少在编译器和运行时级别)发生的事情,如果可能的话,还要了解内存中发生的事情。

1 个答案:

答案 0 :(得分:3)

  

它不知道序列化了哪个类

知道,BinaryFormatter包含流中序列化对象的类型信息。它记录程序集显示名称,程序集版本,程序集的公钥标记,命名空间名称和类型名称。对于类中的每个字段,它记录字段名称和字段类型,与对象类型的操作方式相同。

请注意,这往往会使二进制序列化变得有点危险,反序列化数据的代码需要能够找回 exact 相同的程序集。几年后趋于困难。

通过序列化到FileStream获得更多洞察力,使用十六进制查看器查看数据。您很快就会看到额外的元数据。

  

为什么(问题)someObjectOfTypeObject正在调用特殊的构造函数

因为你继承了ISerializable。 BinaryFormatter检查您是否实现了该接口,然后自动寻找带有Seri​​alizationInfo和StreamingContext参数的构造函数。

更有趣的情况是实现ISerializable。 BinaryFormatter然后拉出一个你不能自己拉开的特技,它创建一个对象,而不用调用构造函数。它在CLR中使用后门来执行此操作。设置字段值然后在最初序列化时将对象重建为存储在内存中的方式。

相关问题