2013-07-25 37 views
22

Vui lòng xem mã bên dưới viết XML ra để gửi một lớp đơn giản chứa danh sách 3 đối tượng. 3 đối tượng trong danh sách đi xuống từ nhau, Base, Derived1, Derived2. Tôi sử dụng XMLArrayItemAttributes để ghi đè các tên trong quá trình tuần tự hóa. Điều này làm việc tốt trong .NET 3.0, nhưng bây giờ kết quả đầu ra khác nhau trong .NET 4.0. Vui lòng xem các Đầu ra dưới đây, lưu ý cụ thể mục con thứ hai DerivedItem2.Nối tiếp XML - kết quả khác nhau trong .NET 4.0

Có ai có kinh nghiệm với điều này và cách tôi có thể sửa chữa nó để làm việc trong .NET 4.0 như nó đã làm trong v3.5?

Dường như tôi không thể kiểm soát thứ tự các mục mảng bị ghi đè. Nó không xuất hiện là thứ tự mà chúng được thêm vào XMLArrayItems.

Chỉnh sửa: Tôi vừa thử ví dụ tương tự bằng cách sử dụng MONO dựa trên các phiên bản 4.0 và 4.5 và nó hoạt động tốt với các phiên bản đó. Có thể đây chỉ là một lỗi với các phiên bản khung công tác của Microsoft không?

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Drawing; 
using System.Linq; 
using System.Text; 
using System.Windows.Forms; 
using System.Collections; 
using System.Xml.Serialization; 
using System.Xml; 
using System.Xml.Schema; 
using System.IO; 


namespace WindowsFormsApplication1 
{ 
public partial class Form1 : Form 
{ 
    public Form1() 
    { 
     InitializeComponent(); 
    } 

    private void button1_Click(object sender, EventArgs e) 
    { 
     TestGroup g = new TestGroup(); 
     XmlSerializer s = new XmlSerializer(typeof(TestGroup), g.GetOverrides()); 
     TextWriter w = new StreamWriter("c:\\#\\test.xml"); 
     s.Serialize(w, g); 
     w.Close(); 
    } 
} 


public class TestGroup 
{ 
    public List<BaseItem> Items { get; set; } 

    public TestGroup() 
    { 
     Items = new List<BaseItem>(); 
     BaseItem b = new BaseItem(); 
     b.BaseName = "Base Name"; 
     Items.Add(b); 
     DerivedItem d1 = new DerivedItem(); 
     d1.BaseName = "D1"; 
     d1.DerivedName = "D1"; 
     Items.Add(d1); 
     DerivedItem2 d2 = new DerivedItem2(); 
     d2.BaseName = "D2"; 
     //d2.DerivedName = "D2"; 
     d2.Derived2Name = "D2"; 
     Items.Add(d2); 
    } 


    public XmlAttributeOverrides GetOverrides() 
    { 
     XmlAttributes atts = new XmlAttributes(); 

     for (int i = 0; i < Items.Count; i++) 
     { 
      BaseItem b = Items[i]; 
      Type ItemType = b.GetType(); 

      XmlArrayItemAttribute ItemAtt = new XmlArrayItemAttribute(); 

      ItemAtt.ElementName = ItemType.Name; 
      ItemAtt.Type = ItemType; 
      atts.XmlArrayItems.Add(ItemAtt); 
     } 

     XmlAttributeOverrides attOvers = new XmlAttributeOverrides(); 
     attOvers.Add(typeof(TestGroup), "Items", atts); 

     return attOvers; 
    } 

} 
public class BaseItem : IXmlSerializable 
{ 
    public string BaseName; 

    public XmlSchema GetSchema() 
    { 
     return null; 
    } 

    public void ReadXml(XmlReader reader) 
    { 
     // not required for example 
    } 

    public virtual void WriteXml(XmlWriter writer) 
    { 
     writer.WriteElementString("BaseName", this.BaseName); 
    } 
} 
public class DerivedItem: BaseItem 
{ 
    public string DerivedName; 

    public override void WriteXml(XmlWriter writer) 
    { 
     base.WriteXml(writer); 
     writer.WriteElementString("DerivedName", this.DerivedName); 
    } 
} 
public class DerivedItem2: DerivedItem 
{ 
    public string Derived2Name; 

    public override void WriteXml(XmlWriter writer) 
    { 
     base.WriteXml(writer); 
     writer.WriteElementString("Derived2Name", this.Derived2Name); 
    } 
} 

Output gốc (.NET 3.0):

<?xml version="1.0" encoding="utf-8"?> 
<TestGroup xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
    <Items> 
    <BaseItem> 
     <BaseName>Base Name</BaseName> 
    </BaseItem> 
    <DerivedItem> 
     <BaseName>D1</BaseName> 
     <DerivedName>D1</DerivedName> 
    </DerivedItem> 
    <DerivedItem2> 
     <BaseName>D2</BaseName> 
     <DerivedName /> 
     <Derived2Name>D2</Derived2Name> 
    </DerivedItem2> 
    </Items> 
</TestGroup> 

Output Changed (.NET 4.0):

<?xml version="1.0" encoding="utf-8"?> 
<TestGroup xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
    <Items> 
    <BaseItem> 
     <BaseName>Base Name</BaseName> 
    </BaseItem> 
    <DerivedItem> 
     <BaseName>D1</BaseName> 
     <DerivedName>D1</DerivedName> 
    </DerivedItem> 
    <DerivedItem> 
     <BaseName>D2</BaseName> 
     <DerivedName /> 
     <Derived2Name>D2</Derived2Name> 
    </DerivedItem> 
    </Items> 
</TestGroup> 

Cập nhật: Output từ NET 4,5

<?xml version="1.0" encoding="utf-8"?> 
<TestGroup xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
    <Items> 
    <BaseItem> 
     <BaseName>Base Name</BaseName> 
    </BaseItem> 
    <BaseItem> 
     <BaseName>D1</BaseName> 
     <DerivedName>D1</DerivedName> 
    </BaseItem> 
    <DerivedItem2> 
     <BaseName>D2</BaseName> 
     <DerivedName /> 
     <Derived2Name>D2</Derived2Name> 
    </DerivedItem2> 
    </Items> 
</TestGroup> 

Cập nhật: Bật o n công tắc gỡ lỗi trong app.config như dưới đây, được tham chiếu từ http://msdn.microsoft.com/en-us/library/aa302290.aspx, tôi thấy rằng thứ tự mà Serialization áp dụng các ghi đè khác với thứ tự mà tôi điền vào mảng ghi đè. Bất cứ ai cũng có ý tưởng làm thế nào thứ tự này được xác định hoặc ghi đè?

<?xml version="1.0" encoding="utf-8" ?> 
<configuration> 
    <system.diagnostics> 
     <switches> 
      <add name="XmlSerialization.Compilation" value="4" /> 
     </switches> 
    </system.diagnostics> 
</configuration> 

này mang lại cho tôi aC# ra tập tin trong đó cho thấy trình tự ghi đè như không chính xác:

void Write2_TestGroup(string n, string ns, global::WindowsFormsApplication1.TestGroup o, bool isNullable, bool needType) { 
    if ((object)o == null) { 
     if (isNullable) WriteNullTagLiteral(n, ns); 
     return; 
    } 
    if (!needType) { 
     System.Type t = o.GetType(); 
     if (t == typeof(global::WindowsFormsApplication1.TestGroup)) { 
     } 
     else { 
      throw CreateUnknownTypeException(o); 
     } 
    } 
    WriteStartElement(n, ns, o, false, null); 
    if (needType) WriteXsiType(@"TestGroup", @""); 
    { 
     global::System.Collections.Generic.List<global::WindowsFormsApplication1.BaseItem> a = (global::System.Collections.Generic.List<global::WindowsFormsApplication1.BaseItem>)((global::System.Collections.Generic.List<global::WindowsFormsApplication1.BaseItem>)[email protected]); 
     if (a != null){ 
      WriteStartElement(@"Items", @"", null, false); 
      for (int ia = 0; ia < ((System.Collections.ICollection)a).Count; ia++) { 
       global::WindowsFormsApplication1.BaseItem ai = (global::WindowsFormsApplication1.BaseItem)a[ia]; 
       if ((object)(ai) != null){ 
        if (ai is global::WindowsFormsApplication1.DerivedItem) { 
         WriteSerializable((System.Xml.Serialization.IXmlSerializable)((global::WindowsFormsApplication1.DerivedItem)ai), @"DerivedItem", @"", true, true); 
        } 
        else if (ai is global::WindowsFormsApplication1.BaseItem) { 
         WriteSerializable((System.Xml.Serialization.IXmlSerializable)((global::WindowsFormsApplication1.BaseItem)ai), @"BaseItem", @"", true, true); 
        } 
        else if (ai is global::WindowsFormsApplication1.DerivedItem2) { 
         WriteSerializable((System.Xml.Serialization.IXmlSerializable)((global::WindowsFormsApplication1.DerivedItem2)ai), @"DerivedItem2", @"", true, true); 
        } 
        else if ((object)(ai) != null){ 
         throw CreateUnknownTypeException(ai); 
        } 
       } 
      } 
      WriteEndElement(); 
     } 
    } 
    WriteEndElement(o); 
} 
+0

Vâng, điều này có vẻ lạ. Bạn đã thử với .net 4.5 chưa? Thứ tự loại 'ai' được kiểm tra chỉ nên là từ loại chuyên biệt nhất đến loại tổng quát nhất, theo suy nghĩ của tôi. Bất cứ điều gì khác không có ý nghĩa vì nó sẽ không bao giờ xuất ra tên kiểu đúng trong XML kèm theo và do đó deserialising sẽ không hoạt động. Bạn đã thử deserialising XML được tạo ra chưa? Bạn có nhận được hành vi tương tự nếu bạn không ghi đè WriteXml() không? – Rory

+0

Có thể có một số khía cạnh khó tính đối với serialiser, ví dụ: bạn đã thử bảo đảm các lớp dẫn xuất của bạn đều có phương thức ReadXml() chưa? – Rory

+0

Cảm ơn các bình luận Rory. Tôi đã thử một vài kết hợp bao gồm/không bao gồm ReadXml/WriteXml và nó vẫn có vẻ như cung cấp cho cùng một tên phần tử cơ sở. Cũng đã thử nó với .NET 4.5 ở cả hai chế độ cũ và không nhưng vẫn không có sự khác biệt. –

Trả lời

4

Vâng Pat,

tôi đã được quản lý để tái tạo cùng một vấn đề khi kiểm tra mã của bạn trong. Net4 và thay đổi thành .Net4.5 ...

Trong .Net4.5 đầu ra có vẻ giống như những gì bạn đã trích dẫn .Net3

Vì vậy, hãy tiếp tục và bỏ qua .Net4 và thay vào đó chỉ sử dụng .Net4.5

Lý do cho vấn đề này bắt nguồn từ cách đối tượng được xây dựng trong bộ nhớ trong khung công tác. Trong .net4 chúng có thể được tổ chức từ "cơ sở" đến "có nguồn gốc" và trong .Net3 và .Net4.5 chúng được tổ chức (chính xác hơn theo ý kiến ​​của tôi và nó là một vấn đề của ý kiến) từ "có nguồn gốc" đến "cơ sở" . Cụ thể hơn về điều đó, tôi tin rằng trong:

.Net4 khuôn khổ lưu trữ cá thể đối tượng dưới dạng cơ sở với con trỏ đến thể hiện được dẫn xuất.

.Net4.5/.Net3 khung làm việc lưu trữ cá thể đối tượng dưới dạng kiểu bắt nguồn với con trỏ đến phiên bản cơ sở.

Trong cả hai trường hợp, bạn sẽ nhận được kết quả tương tự khi làm việc với đối tượng trong các trường hợp thông thường.

Tôi nhớ đọc rằng việc thu thập rác có một số cải tiến trong .net4.5 và tôi tin rằng đây chỉ là một phần của những điều mà các nhà phát triển MS thay đổi để tối ưu hóa hiệu suất.

Trong cả hai bài kiểm tra, tôi đã làm việc với cùng một phiên bản của XML Serializer (4.0)

+0

G.Y, xin lỗi tôi đã không xem xét câu hỏi này trong một thời gian. Cảm ơn vì thông tin. Tôi khá chắc chắn tôi đã thử nghiệm với .NET 4.5 theo nhận xét của tôi về câu hỏi ban đầu (ngày 12 tháng 8). Tôi sẽ phải quay lại và thử lại. Tôi sẽ quay lại ngay. –

+0

Tôi vừa chạy ứng dụng theo .NET 4.5, vui lòng xem phần chỉnh sửa câu hỏi gốc với kết quả. Trong khi đó là một kết quả khác, nó vẫn không cố định. –