gpt4 book ai didi

c# - BinaryFormatter.Deserialize 如何创建新对象?

转载 作者:IT王子 更新时间:2023-10-29 04:31:05 24 4
gpt4 key购买 nike

BinaryFormatter 将流反序列化为对象时,它似乎是在不调用构造函数的情况下创建新对象。

这是怎么做到的?为什么? .NET 中还有其他任何东西可以做到这一点吗?

这是一个演示:

[Serializable]
public class Car
{
public static int constructionCount = 0;

public Car()
{
constructionCount++;
}
}

public class Test
{
public static void Main(string[] args)
{
// Construct a car
Car car1 = new Car();

// Serialize and then deserialize to create a second, identical car
MemoryStream stream = new MemoryStream();
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(stream, car1);
stream.Seek(0, SeekOrigin.Begin);
Car car2 = (Car)formatter.Deserialize(stream);

// Wait, what happened?
Console.WriteLine("Cars constructed: " + Car.constructionCount);
if (car2 != null && car2 != car1)
{
Console.WriteLine("But there are actually two.");
}
}
}

输出:

制造的汽车:1
但实际上有两个。

最佳答案

调用构造函数有两件事(或至少应该做)。

一种是为对象留出一定数量的内存,并进行所有必要的内务处理,使其成为 .NET 世界其他部分的对象(注意本解释中的一定数量的手动操作)。

另一种是将对象置于有效的初始状态,可能基于参数 - 这是构造函数中的实际代码将要做的事情。

反序列化通过调用 FormatterServices.GetUninitializedObject 做与第一步大致相同的事情,然后通过将字段的值设置为等同于那些在序列化期间记录(这可能需要将其他对象反序列化为所述值)。

现在,反序列化将对象放入的状态可能与任何构造函数可能的状态都不对应。最好的情况是浪费(构造函数设置的所有值都将被覆盖),更糟糕的是它可能很危险(构造函数有一些副作用)。这也可能是不可能的(只有构造函数是接受参数的——序列化无法知道要使用什么参数)。

您可以将其视为一种特殊类型的构造函数,仅用于反序列化(面向对象的纯粹主义者将 - 并且应该 - 对不构造的构造函数的想法不寒而栗,我的意思是这只是一个类比,如果你知道C++ 考虑覆盖 new 的方式,就内存而言,你有一个更好的类比,尽管仍然只是一个类比)。

现在,这在某些情况下可能是个问题 - 也许我们有只能由构造函数设置的 readonly 字段,或者我们有想要 发生。

两者的解决方案是使用 ISerializable 覆盖序列化行为。这将基于对 ISerializable.GetObjectData 的调用进行序列化。然后使用 SerializationInfoStreamingContext 字段调用特定的构造函数进行反序列化(所述构造函数甚至可以是私有(private)的 - 这意味着大多数其他代码甚至看不到它)。因此,如果我们可以反序列化 readonly 字段并产生我们想要的任何副作用(我们也可以做各种事情来控制序列化的内容和方式)。

如果我们只关心确保在构造时会发生反序列化的一些副作用,我们可以实现 IDeserializationCallback 并且我们将在反序列化时调用 IDeserializationCallback.OnDeserialization完成了。

至于与此功能相同的其他功能,.NET 中还有其他形式的序列化,但我只知道这些。可以自己调用 FormatterServices.GetUninitializedObject,但除非您有很强的保证后续代码会将生成的对象置于有效状态(即反序列化时您所处的那种情况)来自通过序列化相同类型的对象生成的数据的对象)这样做是令人担忧的,并且是产生真正难以诊断错误的好方法。

关于c# - BinaryFormatter.Deserialize 如何创建新对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3500429/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com