2009-04-29 29 views
71

Tôi đang cố gắng sắp xếp một đối tượng vào XML có một số thuộc tính, một số trong đó là chỉ đọc.Nối tiếp dữ liệu thành viên riêng tư

public Guid Id { get; private set; } 

Tôi đã đánh dấu lớp [Serializable] và tôi đã triển khai giao diện ISerializable.

Dưới đây là mã tôi đang sử dụng để sắp xếp hàng loạt đối tượng của mình.

public void SaveMyObject(MyObject obj) 
{ 
    XmlSerializer serializer = new XmlSerializer(typeof(MyObject)); 
    TextWriter tw = new StreamWriter(_location); 
    serializer.Serialize(tw, obj); 
    tw.Close(); 
} 

Thật không may nó rơi trên dòng đầu tiên với thông báo này.

InvalidOperationException unhandled: Không thể tạo lớp tạm thời (kết quả = 1). lỗi CS0200: Không thể chỉ định thuộc tính hoặc chỉ mục 'MyObject.Id' - chỉ đọc được

Nếu tôi đặt thuộc tính Id thành công khai, hoạt động tốt. Ai đó có thể cho tôi biết nếu tôi đang làm điều gì đó, hoặc ít nhất là nếu nó có thể xảy ra?

Trả lời

57

Bạn có thể sử dụng DataContractSerializer (nhưng lưu ý bạn không thể sử dụng xml thuộc tính - chỉ yếu tố xml):

using System; 
using System.Runtime.Serialization; 
using System.Xml; 
[DataContract] 
class MyObject { 
    public MyObject(Guid id) { this.id = id; } 
    [DataMember(Name="Id")] 
    private Guid id; 
    public Guid Id { get {return id;}} 
} 
static class Program { 
    static void Main() { 
     var ser = new DataContractSerializer(typeof(MyObject)); 
     var obj = new MyObject(Guid.NewGuid()); 
     using(XmlWriter xw = XmlWriter.Create(Console.Out)) { 
      ser.WriteObject(xw, obj); 
     } 
    } 
} 

Ngoài ra, bạn có thể thực hiện IXmlSerializable và làm tất cả mọi thứ cho mình - nhưng công trình này với XmlSerializer, ít nhất .

+0

+1, cảm ơn lời khuyên của tôi về câu trả lời của tôi. –

+0

Tôi đã thay đổi mã của mình để sử dụng DataContractSerializer và tôi nhận thấy rằng nó vẫn đang chạy phương thức GetObjectData. Tôi có nghĩ rằng tôi có thể đặt các thuộc tính vào các thuộc tính của tôi để tuần tự hóa chúng hay tôi có thể triển khai giao diện ISerializable không? –

+0

Nếu bạn thực hiện ISerializable (hoặc là IXmlSeializable?), Bạn đang làm tất cả các công việc cho mình ... –

6

Bạn có thể sử dụng System.Runtime.Serialization.NetDataContractSerializer. Nó mạnh hơn và sửa một số vấn đề của Xml Serializer cổ điển.

Lưu ý rằng có các thuộc tính khác nhau cho tính năng này.

[DataContract] 
public class X 
{ 
    [DataMember] 
    public Guid Id { get; private set; } 
} 


NetDataContractSerializer serializer = new NetDataContractSerializer(); 
TextWriter tw = new StreamWriter(_location); 
serializer.Serialize(tw, obj); 

Edit:

Cập nhật dựa trên nhận xét của Marc: Bạn có lẽ nên sử dụng System.Runtime.Serialization.DataContractSerializer cho trường hợp của bạn để có được một XML sạch. Phần còn lại của mã là như nhau.

+0

NetDataContractSerializer không ghi xml ... - hay đúng hơn, nó không phải là xml sạch phù hợp cho tiêu thụ bên ngoài - nó có siêu dữ liệu lắp ráp trong đó. –

+0

@Marc: Cảm ơn gợi ý. Nó luôn phụ thuộc vào những gì người ta muốn đạt được. DataContractSerializer có lẽ là những gì được mong đợi ở đây. –

1

Đọc chỉ lĩnh vực sẽ không được tuần tự bằng cách sử dụng XmlSerializer, điều này là do bản chất của readonly từ khóa

Từ MSDN:

Các readonly từ khóa là một modifier mà bạn có thể sử dụng trên các trường. Khi một khai báo trường bao gồm một công cụ sửa đổi chỉ đọc, các phép gán cho các trường được giới thiệu bởi khai báo chỉ có thể xảy ra như một phần của khai báo hoặc trong một hàm tạo trong cùng một lớp.

... Vì vậy, bạn sẽ khá nhiều cần phải thiết lập giá trị trường trong constructor mặc định ...

+0

Tôi nghĩ rằng vì tôi đã triển khai phương thức ISerializable.GetObjectData nên XmlSerializer sẽ sử dụng nó để lấy thông tin tôi muốn tuần tự hóa và không thử truy cập các thuộc tính chỉ đọc của tôi . –

+0

XmlSerializer không quan tâm đến ISerializable - chỉ IXmlSerializable –

+0

Marc cảm ơn, có ý nghĩa. –

0

của nó không thể thực hiện với chế độ đặc biệt serialization (xem các ý kiến ​​khác cho cách giải quyết). Nếu bạn thực sự muốn rời khỏi chế độ tuần tự hóa của mình, bạn phải làm việc xung quanh các hạn chế của khung công tác này.Xem điều này example

Thực hiện, đánh dấu thuộc tính public, nhưng ném ngoại lệ nếu nó được truy cập bất kỳ lúc nào ngoài deserialization.

+5

"nhưng ném một ngoại lệ" - vì XmlSerializer không hỗ trợ gọi lại serialization, bạn không có cách nào để biết ... –

+1

Bạn có thể sử dụng 'System.Diagnostics.StackTrace' để tìm hiểu điều gì đang gọi thuộc tính của bạn, nhưng tôi sẽ không đề nghị một giải pháp như vậy :-) –

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