[英]DataContractSerializer doesn't call my constructor?
I just realized something crazy, which I assumed to be completely impossible : when deserializing an object, the DataContractSerializer doesn't call the constructor !我刚刚意识到一些疯狂的事情,我认为这是完全不可能的:反序列化对象时, DataContractSerializer 不会调用构造函数!
Take this class, for instance :以这个类为例:
[DataContract]
public class Book
{
public Book()
{ // breakpoint here
}
[DataMember(Order = 0)]
public string Title { get; set; }
[DataMember(Order = 1)]
public string Author { get; set; }
[DataMember(Order = 2)]
public string Summary { get; set; }
}
When I deserialize an object of that class, the breakpoint is not hit.当我反序列化那个类的对象时,断点没有被命中。 I have absolutely no idea how it is possible, since it is the only constructor for this object !
我完全不知道这是怎么可能的,因为它是这个对象的唯一构造函数!
I assumed that perhaps an additional constructor was generated by the compiler because of the DataContract
attribute, but I couldn't find it through reflection...我假设编译器可能因为
DataContract
属性而生成了一个额外的构造函数,但是我无法通过反射找到它...
So, what I'd like to know is this : how could an instance of my class be created without the constructor being called ??所以,我想知道的是:如何在不调用构造函数的情况下创建我的类的实例?
NOTE: I know that I can use the OnDeserializing
attribute to initialize my object when deserialization begins, this is not the subject of my question.注意:我知道我可以在反序列化开始时使用
OnDeserializing
属性来初始化我的对象,这不是我的问题的主题。
DataContractSerializer
(like BinaryFormatter
) doesn't use any constructor. DataContractSerializer
(如BinaryFormatter
)不使用任何构造函数。 It creates the object as empty memory.它将对象创建为空内存。
For example:例如:
Type type = typeof(Customer);
object obj = System.Runtime.Serialization.
FormatterServices.GetUninitializedObject(type);
The assumption is that the deserialization process (or callbacks if necessary) will fully initialize it.假设是反序列化过程(或必要时回调)将完全初始化它。
There are some scenario's that wouldn't be possible without this behavior.如果没有这种行为,有些情况是不可能的。 Think of the following:
考虑以下几点:
1) You have an object that has one constructor that sets the new instance to an "initialized" state. 1) 您有一个对象,该对象具有一个构造函数,该构造函数将新实例设置为“已初始化”状态。 Then some methods are called on that instance, that bring it in a "processed" state.
然后在该实例上调用一些方法,使其处于“已处理”状态。 You don't want to create new objects having the "processed" state, but you still want de serialize / deserialize the instance.
您不想创建具有“已处理”状态的新对象,但您仍希望对实例进行反序列化/反序列化。
2) You created a class with a private constructor and some static properties to control a small set of allowed constructor parameters. 2) 您创建了一个带有私有构造函数和一些静态属性的类来控制一小组允许的构造函数参数。 Now you can still serialize / deserialize them.
现在您仍然可以序列化/反序列化它们。
XmlSerializer has the behavior you expected. XmlSerializer 具有您预期的行为。 I have had a some problems with the XmlSerializer because it DOES need a default constructor.
我在使用 XmlSerializer 时遇到了一些问题,因为它确实需要一个默认构造函数。 Related to that, sometimes it makes sense to have private property setters.
与此相关,有时拥有私有财产设定者是有意义的。 But the XmlSerializer also needs public getter and setter on properties in order to serialize / deserialize.
但是 XmlSerializer 还需要属性上的公共 getter 和 setter,以便序列化/反序列化。
I think of the DataContractSerializer / BinaryFormatter behavior like suspending the state of an instance during serialization and resuming during deserialization.我想到了 DataContractSerializer / BinaryFormatter 行为,例如在序列化期间暂停实例的状态并在反序列化期间恢复。 In other words, the instances are not “constructed” but “restored” to an earlier state.
换句话说,实例不是“构造”而是“恢复”到较早的状态。
As you already mentioned, the [OnDeserializing] attribute makes it possible to keep non serialized data in sync.正如您已经提到的,[OnDeserializing] 属性可以使非序列化数据保持同步。
FWIW, you can call the constructor explicitly from a [OnDeserializing] method: FWIW,您可以从 [OnDeserializing] 方法显式调用构造函数:
[OnDeserializing]
public void OnDeserializing(StreamingContext context)
{
this.GetType().GetConstructor(System.Array.Empty<Type>()).Invoke(this, null);
}
Use [OnDeserialized] attribute to initialise your properties.使用 [OnDeserialized] 属性来初始化您的属性。
// This method is called after the object
// is completely deserialized. Use it instead of the
// constructror.
[OnDeserialized]
void OnDeserialized(StreamingContext context)
{
fullName = firstName + " " + lastName;
}
Please refer to microsoft guid-lines: https://docs.microsoft.com/en-us/dotnet/standard/serialization/serialization-guidelines请参考微软指南: https : //docs.microsoft.com/en-us/dotnet/standard/serialization/serialization-guidelines
In my case, i wanted to create an object to use in a lock-clause.就我而言,我想创建一个对象以在锁定子句中使用。 I tried implementing IDeserializationCallback (didn't work because callback only runs after properties have been assigned), [OnDeserialized] (didn't work, same previous reason), and ISerializable (didn't work because the class is decorated with the [DataContractAttribute]).
我尝试实现 IDeserializationCallback(不起作用,因为回调仅在分配属性后运行)、[OnDeserialized](不起作用,与之前的原因相同)和 ISerializable(不起作用,因为该类用 [DataContractAttribute ])。
My workaround was to initialize the field before it's used using Interlocked.CompareExchange.我的解决方法是在使用 Interlocked.CompareExchange 之前初始化该字段。 A bit of unnecessary work gets done, but at least now my field gets initialized when a DataContractSerializer creates it.
一些不必要的工作已经完成,但至少现在我的字段在 DataContractSerializer 创建它时被初始化。
Interlocked.CompareExchange(ref _sync, new object(), null);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.