2009-05-20 26 views
5

Tôi mới vào C# XmlSerializer vì vậy tôi có thể thiếu một cái gì đó cơ bản ở đây.XmlSerializer.Deserialize() không phải là deserializing một Danh sách <T> chính xác

Vấn đề tôi đang gặp phải là tôi có một lớp học có List<T> của một lớp khác. Khi tôi tuần tự hóa lớp chính, XML trông đẹp và tất cả dữ liệu vẫn còn nguyên vẹn. Khi tôi deserialize XML, dữ liệu trong các List<T> biến mất và tôi còn lại với một trống rỗng List<T>. Tôi không nhận được bất kỳ lỗi nào và phần tuần tự hóa hoạt động như sự quyến rũ.

Tôi đang thiếu gì với quá trình deserialization?

EDIT: Lưu ý rằng mã được hiển thị bên dưới không tái tạo sự cố - nó hoạt động. Đây là phiên bản đơn giản của mã thực, đã làm việc không hoạt động. Thật không may, mã dưới đây đã được đơn giản hóa đủ để không tái tạo vấn đề!

public class User 
{ 
    public User() 
    { 
    this.Characters = new List<Character>(); 
    } 
    public string Username { get; set; } 
    public List<Character> Characters { get; set; } 
} 

public class Character 
{ 
    public Character() 
    { 
    this.Skills = new List<Skill>(); 
    } 
    public string Name { get; set; } 
    public List<Skill> Skills { get; set; } 
} 

public enum Skill 
{ 
    TreeClimber, 
    ForkliftOperator 
} 

public static void Save(User user) 
{ 
    using (var textWriter = new StreamWriter("data.xml")) 
    { 
     var xmlSerializer = new XmlSerializer(typeof(User)); 
     xmlSerializer.Serialize(textWriter, user); 
    } 
} 

public static User Restore() 
{ 
    if (!File.Exists("data.xml")) 
     throw new FileNotFoundException("data.xml"); 

    using (var textReader = new StreamReader("data.xml")) 
    { 
     var xmlSerializer = new XmlSerializer(typeof(User)); 
     return (User)xmlSerializer.Deserialize(textReader); 
    } 
} 

public void CreateAndSave() 
{ 
    var character = new Character(); 
    character.Name = "Tranzor Z"; 
    character.Skills.Add(Skill.TreeClimber); 

    var user = new User(); 
    user.Username = "Somebody"; 
    user.Characters.Add(character); 

    Save(user); 
} 

public void RestoreAndPrint() 
{ 
    var user = Restore(); 
    Console.WriteLine("Username: {0}", user.Username); 
    Console.WriteLine("Characters: {0}", user.Characters.Count); 
} 

XML được tạo ra bằng cách thực hiện CreateAndSave() trông giống như vậy:

<User> 
    <Username>Somebody</Username> 
    <Characters> 
    <Character> 
     <Name>Tranzor Z</Name> 
     <Skills> 
     <Skill>TreeClimber</Skill> 
     </Skills> 
    </Character> 
    <Characters> 
</User> 

Perfect! Đó là cách nó nên nhìn. Nếu tôi sau đó thực hiện RestoreAndPrint() tôi nhận được một đối tượng người dùng với tài sản Tên thiết lập đúng nhưng nhân vật sở hữu là một danh sách rỗng:

Username: Somebody 
Characters: 0 

Ai có thể giải thích cho tôi tại sao sở hữu nhân vật được đăng đúng nhưng sẽ không deserialize?

+3

bạn không cần [Serializable] trên các loại. Hành vi của Xml Serializer hoàn toàn độc lập với thuộc tính đó. – Cheeso

+0

OK; vì vậy kể từ khi chúng tôi (hoặc tôi, ít nhất) nghi ngờ vấn đề là trong mã "thực" (không được hiển thị); bạn có làm bất cứ điều gì thú vị trong bộ truy cập "set" của danh sách không? Đó sẽ là nơi đầu tiên tôi nhìn. –

+0

Không, chúng là tất cả các thuộc tính cơ bản không có gì lạ mắt trong các trình truy cập nhận hoặc đặt. Tất cả họ trông giống như vậy: công khai T PropertyName {get; bộ; } – Andy

Trả lời

1

Sau khi sử dụng mã lệnh trong một thời gian dài, cuối cùng tôi đã từ bỏ ý tưởng sử dụng hành vi mặc định của XmlSerializer.

Tất cả các lớp liên quan hiện kế thừa IXmlSerializer và triển khai các hàm ReadXml() và WriteXml(). Tôi đã thực sự hy vọng để có những tuyến đường lười biếng nhưng bây giờ mà tôi đã chơi với IXmlSerializer tôi nhận ra rằng nó thực sự không phải là khó khăn cả và sự linh hoạt thêm là thực sự tốt đẹp.

-2

Nó có thể phải làm với deserializing của enum .... kể từ khi nó tuần tự hóa nó như là giá trị chuỗi ... có thể gặp khó khăn trong việc tạo ra giá trị enum chính xác cho nhân vật. Chưa thử nghiệm giả thuyết này ...

+0

Trong dự án mã thực tế của tôi, lớp gốc không có các enums khác đang được tuần tự hóa và deserialized đúng cách. Tôi có thể tuần tự hóa và deserialize các đối tượng riêng lẻ trong danh sách Ký tự thành công. Nó chỉ là khi deserializing một đối tượng người dùng mà quá trình phá vỡ và danh sách nhân vật là sản phẩm nào và không có ngoại lệ đang được ném. – Andy

+0

-1: không có vấn đề với enum. Tôi khuyên bạn nên thử nghiệm trong tương lai hoặc không nói gì cả. –

0
Stream stream = File.Open(filename + ".xml", FileMode.Open); 
User user = null; 
using (XmlReader reader = XmlReader.Create(stream)) 
{ 
    user = IntermediateSerializer.Deserialize<User>(reader, null); 
} 
stream.Close(); 

return user; 

Tôi sẽ thử sử dụng một cái gì đó như thế này.

+0

Mã tôi đang làm việc với * là * liên quan đến trò chơi nhưng tôi không tham chiếu Khung XNA trong dự án này vì vậy tôi không có quyền truy cập vào Trình điều khiển trung gian. – Andy

+0

Xin lỗi, tôi đã đưa ra giả định. –

5

Không thể tái tạo; Tôi nhận được (sau khi sửa chữa các lỗi trực tiếp hơn):

Username: Somebody 
Characters: 1 

Thay đổi:

  • WriteLine thay vì WriteFormat (mà ngăn cản nó biên dịch)
  • init danh sách qua các nhà xây dựng mặc định (trong đó ngăn chặn CreateAndSave từ nơi làm việc):
    • public User() { Characters = new List<Character>(); }
    • public Character() { Skills = new List<Skill>(); }
+1

Hrm ... Mã tôi đăng ở trên là mã mẫu bắt chước mã thực sự của tôi, do đó, những sai lầm của tôi, xin lỗi 'bout đó. Dự án thực tế của tôi lớn hơn đáng kể nhưng mã được đăng là một xấp xỉ gần đúng như những gì tôi đang cố gắng làm. Mục đích của tôi là cung cấp một ví dụ đại diện cho tình huống của tôi mà không cung cấp tất cả các chi tiết đẫm máu. :/ – Andy

+0

Thật không may, tôi nghĩ rằng vấn đề là trong mã được bỏ qua. –

+0

Heh.Tôi sẽ xem xét một protobuf-net nhưng mục tiêu của tôi cho dự án này là một định dạng con người có thể đọc/chỉnh sửa có thể được thao tác với bất kỳ trình soạn thảo văn bản cơ bản nào. – Andy

2

Trong quá khứ, khi tuần tự danh sách, tôi đã sử dụng [XmlArray] và [XmlArrayItem] chú thích. Sau đó, bạn sẽ đặt chú thích [XmlIgnore] vào thuộc tính Ký tự. Trong trường hợp của bạn, nó sẽ trông giống như sau:

[XmlArray("Characters")] 
[XmlArrayItem("Character", Type=typeof(Character))] 
public Character[] _ Characters 
{ 
    get 
    { 
     //Make an array of Characters to return 
     return Characters.ToArray(); 
    } 

    set 
    { 
     Characters.Clear(); 
     for(int i = 0; i < value.Length; i++) 
      Characters.Add(value[i]); 
    } 
} 

Hy vọng điều đó sẽ hữu ích.

+0

Không may mắn - tôi nhận được kết quả tương tự, tức là danh sách trống. Khi tôi deserialize, không ai trong số các mã liên quan đến nhân vật đang được xúc động. Nó giống như toàn bộ nút Nhân vật trong XML đang bị vứt bỏ mà không được xử lý. – Andy

1

Có lẽ, thay vì một StreamReader, thay vào đó hãy tạo một XmlReader. Ngoài ra, dưới dạng bước khắc phục sự cố, bạn có thể thử mã hiện tại của mình bằng các loại rõ ràng (như bên dưới) thay vì khai báo "var".

public static User Restore() 
{ 
    if (!File.Exists("data.xml")) 
    throw new FileNotFoundException("data.xml"); 

    XmlReader xr = XmlReader.Create("data.xml"); 
    XmlSerializer serializer = new XmlSerializer(typeof(User)); 
    var user = (User)serializer.Deserialize(xr); 
    xr.Close(); 
    return user; 
} 

EDIT: Ngoài ra, hãy thử chú thích XmlInclude trên lớp người dùng của bạn.

[XmlInclude(typeof(Character))] 
+0

Tôi đã thêm XmlIncludeAttributes vào tất cả các lớp có liên quan và quá trình deserialization vẫn không thành công. – Andy

0

tôi đã thêm thuộc tính này để loại Danh sách của tôi và nó làm việc sau đó (có cùng một vấn đề của bạn):

[System.Xml.Serialization.XmlElementAttribute("NameOfMyField")] 
public List<SomeType> NameOfMyField{get;set;} 

Tôi nghĩ rằng đây là giải pháp của bạn.

1

Tôi biết điều này là cũ nhưng tôi có cùng một vấn đề.

Điều tôi thấy là nếu tôi có một đối tượng thực hiện IXmlSerializable trong đồ thị (vì vậy đối tượng chính mà tôi muốn deserialize không thực hiện giao diện, nhưng một đối tượng trong nó thực hiện nó), nó hủy hoại tất cả deserialization. Danh sách không deserialize nữa, không phải là đối tượng tôi đang nói về. Serialization hoạt động hoàn hảo.

+3

phát hiện ra lý do: trong ReadXml cẩn thận để nâng cao trình đọc cho thẻ đóng. –

+1

làm cho một quan sát rất tốt là rất quan trọng nếu bạn đã thực hiện IXmlSerializable - hãy chắc chắn rằng bạn hoàn thành với reader.ReadEndElement(); ở phần cuối của logic đọc xml tùy chỉnh của bạn –

+0

Ước gì tôi có thể upvote bạn cả mười lần ... Tại sao trên trái đất bài viết MSDN tôi sao chép mã từ nguyên văn có lỗi này? – vines

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