2008-11-06 26 views
146

Tôi đang viết mã để làm xml serialization. Với chức năng dưới đây.Tại sao lớp XML-Serializable cần một hàm tạo tham số

public static string SerializeToXml(object obj) 
{ 
    XmlSerializer serializer = new XmlSerializer(obj.GetType()); 
    using (StringWriter writer = new StringWriter()) 
    { 
     serializer.Serialize(writer, obj); 
     return writer.ToString(); 
    } 
} 

Nếu đối số là một thể hiện của lớp không có hàm tạo tham số, nó sẽ ném một ngoại lệ.

Unhandled Exception: System.InvalidOperationException: CSharpConsole.Foo không thể được đăng bởi vì nó không có một constructor parameterless. tại System.Xml.Serialization.TypeDesc.CheckSupported() tại System.Xml.Serialization.TypeScope.GetTypeDesc (Type loại, MemberInfo sourc e, Boolean directReference, Boolean throwOnError) tại System.Xml.Serialization. ModelScope.GetTypeModel (Type loại, Boolean tham khảo trực tiếp) tại System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping (Type loại, XmlRootAttribute gốc, string defaultNamespace) tại System.Xml.Serialization.XmlSerializer..ctor (Type loại, String defaultName không gian) tại System.Xml.Serialization.XmlSerializer..ctor (Loại type)

Tại sao phải có một hàm tạo tham số để cho phép xml serialization thành công?

CHỈNH SỬA: cảm ơn câu trả lời của cfeduke. Các constructor parameterless có thể được tư nhân hoặc nội bộ.

+1

Nếu bạn quan tâm, tôi tìm thấy cách tạo đối tượng mà không cần hàm tạo (xem cập nhật) - nhưng điều này sẽ không giúp XmlSerializer chút nào - nó vẫn yêu cầu nó. Hữu ích cho mã tùy chỉnh, có thể. –

+0

'XmlSerializer' yêu cầu một hàm tạo parameterless mặc định cho việc deserialization. –

Trả lời

208

Khi loại bỏ tuần tự một đối tượng, lớp chịu trách nhiệm loại bỏ một đối tượng tạo một thể hiện của lớp được tuần tự hóa và sau đó tiến hành điền các trường và thuộc tính được tuần tự hóa sau khi có một cá thể.

Bạn có thể tạo hàm tạo của mình private hoặc internal nếu bạn muốn, miễn là không tham số của nó.

+0

Ồ, vì vậy, tôi có thể làm cho ctor parameterless tư nhân hoặc nội bộ và serialization vẫn hoạt động. Cảm ơn câu trả lời của bạn. –

+1

Có, tôi thường xuyên làm điều đó, mặc dù tôi đã chấp nhận rằng các nhà xây dựng không có tham số công khai là tuyệt vời bởi vì chúng cho phép bạn sử dụng "new()" với Generics và cú pháp khởi tạo mới. Đối với các nhà xây dựng có tham số sử dụng các phương thức nhà máy tĩnh hoặc triển khai thực hiện mẫu trình xây dựng. – cfeduke

+11

Mẹo trợ năng là một mẹo tốt, nhưng lời giải thích của bạn không có ý nghĩa đối với việc tuần tự hóa. Một đối tượng cần phải được tạo ra chỉ cho de-serialization. Tôi rất nguy hiểm khi đoán rằng mã kiểm tra kiểu được tích hợp vào hàm tạo XmlSerializer vì một cá thể đơn có thể được sử dụng theo cả hai cách. –

0

Trước hết, nội dung này được viết bằng documentation. Tôi nghĩ rằng đó là một trong những lĩnh vực lớp học của bạn, không phải là một trong những chính - và làm thế nào bạn muốn deserialiser để xây dựng nó trở lại w/o xây dựng parameterless?

Tôi nghĩ rằng có một giải pháp thay thế để làm cho hàm tạo riêng tư.

65

Đây là giới hạn của XmlSerializer. Lưu ý rằng BinaryFormatterDataContractSerializerkhông yêu cầu điều này - chúng có thể tạo ra một đối tượng chưa được khởi tạo ra khỏi ether và khởi tạo nó trong quá trình deserialization.

Vì bạn đang sử dụng xml, bạn có thể xem xét sử dụng DataContractSerializer và đánh dấu lớp học của bạn với [DataContract]/[DataMember], nhưng lưu ý rằng điều này thay đổi giản đồ (ví dụ, không có tương đương với [XmlAttribute] - mọi thứ trở nên yếu tố).

Cập nhật: nếu bạn thực sự muốn biết, BinaryFormatter et al use FormatterServices.GetUninitializedObject() để tạo đối tượng mà không cần gọi hàm tạo.Có lẽ nguy hiểm; Tôi không khuyên bạn sử dụng nó quá thường xuyên ;-p Xem thêm các nhận xét trên MSDN:

Bởi vì các trường hợp mới của đối tượng được khởi tạo bằng không và không có nhà xây dựng đang chạy, đối tượng có thể không đại diện cho một trạng thái được coi là là hợp lệ bởi đối tượng đó. Phương pháp hiện tại chỉ nên được sử dụng cho cách ly hóa khi người dùng dự định để điền ngay tất cả các trường. Nó không tạo ra một chuỗi chưa được khởi tạo, vì việc tạo ra một thể hiện trống của một loại không thể phục vụ phục vụ không có mục đích.

Tôi có động cơ tuần tự own của mình, nhưng tôi không định làm cho nó sử dụng FormatterServices; Tôi khá thích biết rằng một nhà xây dựng (bất kỳ nhà xây dựng) nào đã thực sự được thi hành.

+0

Cảm ơn mẹo về FormatterServices.GetUninitializedObject (Type). :) –

+4

Heh; hóa ra tôi không theo lời khuyên của tôi; protobuf-net có (tùy ý) cho phép sử dụng 'FormatterServices' cho * age * –

+1

Nhưng điều tôi không hiểu là, trong trường hợp không có hàm tạo nào được chỉ định, trình biên dịch tạo ra một hàm tạo tham số công khai. Vậy tại sao không đủ tốt cho động cơ deserialization xml? – toddmo

Các vấn đề liên quan