DataContractSerializer 不调用我的构造函数?

发布于 2024-07-25 23:42:01 字数 700 浏览 9 评论 0原文

我刚刚意识到一些疯狂的事情,我认为这是完全不可能的:反序列化对象时,DataContractSerializer 不会调用构造函数

以此类为例:

[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; }
}

当我反序列化该类的对象时,不会命中断点。 我完全不知道这是怎么可能的,因为它是这个对象的唯一构造函数!

我假设由于 DataContract 属性,编译器可能生成了一个额外的构造函数,但我无法通过反射找到它......

所以,我想知道的是:如何可以在不调用构造函数的情况下创建我的类的实例吗?

注意:我知道我可以在反序列化开始时使用 OnDeserializing 属性来初始化我的对象,这不是我的问题的主题。

I just realized something crazy, which I assumed to be completely impossible : when deserializing an object, the DataContractSerializer doesn't call the constructor !

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...

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

靑春怀旧 2024-08-01 23:42:01

DataContractSerializer(如BinaryFormatter)不使用任何构造函数。 它将对象创建为空内存。

例如:

    Type type = typeof(Customer);
    object obj = System.Runtime.Serialization.
        FormatterServices.GetUninitializedObject(type);

假设反序列化过程(或必要时回调)将完全初始化它。

DataContractSerializer (like BinaryFormatter) doesn't use any constructor. 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.

﹏半生如梦愿梦如真 2024-08-01 23:42:01

如果没有这种行为,某些场景是不可能实现的。 请考虑以下情况:

1) 您有一个对象,该对象具有一个构造函数,该构造函数将新实例设置为“初始化”状态。 然后在该实例上调用一些方法,使其进入“已处理”状态。 您不想创建具有“已处理”状态的新对象,但您仍然希望对实例进行反序列化/反序列化。

2) 您创建了一个具有私有构造函数和一些静态属性的类来控制一小组允许的构造函数参数。 现在您仍然可以序列化/反序列化它们。

XmlSerializer 具有您期望的行为。 我在使用 XmlSerializer 时遇到了一些问题,因为它确实需要默认构造函数。 与此相关的是,有时拥有私有财产设置者是有意义的。 但 XmlSerializer 还需要属性上的公共 getter 和 setter 以便序列化/反序列化。

我认为 DataContractSerializer / BinaryFormatter 行为例如在序列化期间暂停实例的状态并在反序列化期间恢复。 换句话说,实例不是“构造”的,而是“恢复”到较早的状态的。

正如您已经提到的,[OnDeserializing] 属性可以使非序列化数据保持同步。

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. 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. Now you can still serialize / deserialize them.

XmlSerializer has the behavior you expected. I have had a some problems with the XmlSerializer because it DOES need a default constructor. 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.

I think of the DataContractSerializer / BinaryFormatter behavior like suspending the state of an instance during serialization and resuming during deserialization. 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.

杀手六號 2024-08-01 23:42:01

FWIW,您可以从 [OnDeserializing] 方法显式调用构造函数:

[OnDeserializing]
public void OnDeserializing(StreamingContext context)
{
    this.GetType().GetConstructor(System.Array.Empty<Type>()).Invoke(this, null);
}

FWIW, you can call the constructor explicitly from a [OnDeserializing] method:

[OnDeserializing]
public void OnDeserializing(StreamingContext context)
{
    this.GetType().GetConstructor(System.Array.Empty<Type>()).Invoke(this, null);
}
残龙傲雪 2024-08-01 23:42:01

使用 [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;
}

请参考微软指南:
https://learn.microsoft.com/en-us/ dotnet/标准/序列化/序列化指南

Use [OnDeserialized] attribute to initialise your properties.

// 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://learn.microsoft.com/en-us/dotnet/standard/serialization/serialization-guidelines

小红帽 2024-08-01 23:42:01

就我而言,我想创建一个在锁定子句中使用的对象。 我尝试实现 IDeserializationCallback(不起作用,因为回调仅在分配属性后运行)、[OnDeserialized](不起作用,与之前的原因相同)和 ISerialized(不起作用,因为类用 [DataContractAttribute] 装饰)。

我的解决方法是在使用 Interlocked.CompareExchange 之前初始化该字段。 完成了一些不必要的工作,但至少现在当 DataContractSerializer 创建它时我的字段被初始化。

Interlocked.CompareExchange(ref _sync, new object(), null);

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]).

My workaround was to initialize the field before it's used using Interlocked.CompareExchange. A bit of unnecessary work gets done, but at least now my field gets initialized when a DataContractSerializer creates it.

Interlocked.CompareExchange(ref _sync, new object(), null);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文