2009-07-02 7 views
84

Tôi vừa mới nhận ra điều gì đó điên rồ, mà tôi cho là hoàn toàn không thể: khi deserializing một đối tượng, DataContractSerializer không gọi hàm tạo!DataContractSerializer không gọi hàm tạo của tôi?

Đi lớp này, ví dụ:

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

Khi tôi deserialize một đối tượng của lớp đó, breakpoint không phải là hit. Tôi hoàn toàn không có ý tưởng làm thế nào nó có thể, vì nó là nhà xây dựng duy nhất cho đối tượng này!

Tôi cho rằng có lẽ một nhà xây dựng bổ sung được tạo ra bởi trình biên dịch do đặc tính DataContract, nhưng tôi không thể tìm thấy nó thông qua phản ánh ...

Vì vậy, những gì tôi muốn biết là thế này: làm thế nào có thể một thể hiện của lớp học của tôi được tạo ra mà không có constructor được gọi là ??

LƯU Ý: Tôi biết rằng tôi có thể sử dụng thuộc tính OnDeserializing để khởi tạo đối tượng của mình khi bắt đầu quá trình deserialization, đây không phải là chủ đề của câu hỏi của tôi.

+3

hoặc "OnDeserialized", khi đối tượng được thực hiện deserializing, để điền vào các trường bị thiếu. –

+1

Câu hỏi này cũng đã vượt qua tâm trí của tôi: http://stackoverflow.com/questions/178645/how-does-wcf-deserialization-instantiate-objects-without-calling-a-constructor –

Trả lời

118

DataContractSerializer (như BinaryFormatter) không sử dụng bất kỳ phương thức khởi tạo nào. Nó tạo ra đối tượng như là bộ nhớ trống.

Ví dụ:

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

Giả định là quá trình deserialization (hoặc callbacks nếu cần) hoàn toàn sẽ khởi tạo nó.

+82

Đây là điều đáng sợ !! – Cheeso

+0

Hàm tạo nên không được gọi khi nào deserializing. Nếu nó được gọi, sau đó 1) Làm thế nào về các nguồn lực bạn đã tạo trong constructor? Họ sẽ bị rò rỉ! 2) Bạn đang khởi tạo đối tượng hai lần, một lần trong hàm tạo và một lần bằng các giá trị được deserialized. – Dudu

+1

@Dodu a: điều đó sẽ không gây ra sự rò rỉ b: rằng (gọi ctor) là làm thế nào rất nhiều serializers làm việc; một trong hai cách nói chung là tốt như đăng nhập như hành vi được hiểu và thiết kế theo –

3

Có một số trường hợp không thể thực hiện được nếu không có hành vi này. Hãy suy nghĩ về những điều sau đây:

1) Bạn có một đối tượng có một hàm tạo đặt cá thể mới thành trạng thái "được khởi tạo". Sau đó, một số phương thức được gọi trên cá thể đó, mang nó vào trạng thái "đã xử lý". Bạn không muốn tạo các đối tượng mới có trạng thái "đã xử lý", nhưng bạn vẫn muốn de serialize/deserialize cá thể.

2) Bạn đã tạo một lớp với một hàm tạo riêng và một số thuộc tính tĩnh để kiểm soát một tập nhỏ các tham số hàm dựng được phép. Bây giờ bạn vẫn có thể tuần tự hóa/deserialize chúng.

XmlSerializer có hành vi bạn mong đợi. Tôi đã có một số vấn đề với XmlSerializer vì nó cần một constructor mặc định. Liên quan đến điều đó, đôi khi nó có ý nghĩa để có setters tài sản tư nhân. Nhưng XmlSerializer cũng cần getter công cộng và setter trên các thuộc tính để serialize/deserialize.

Tôi nghĩ về hành vi DataContractSerializer/BinaryFormatter như tạm dừng trạng thái của một cá thể trong quá trình tuần tự và tiếp tục trong quá trình deserialization. Nói cách khác, các trường hợp không được "xây dựng" nhưng "phục hồi" cho một trạng thái trước đó.

Như bạn đã đề cập, thuộc tính [OnDeserializing] làm cho nó có thể giữ dữ liệu không được tuần tự hóa đồng bộ.

+0

Tôi sẽ không nói rằng nó "đình chỉ trạng thái của một cá thể" bởi vì tôi chỉ nhấn một vấn đề mà DataMember của tôi đang sử dụng INotifyPropertyChanged và trong khi constructor không được gọi, nó sẽ kích hoạt NotifyPropertyChanged để hành vi sẽ không bị đình chỉ. – ForceMagic