2013-07-25 4 views
22

См. Ниже код, который записывает XML-файл, чтобы записать простой класс, содержащий список из трех объектов. 3 объекта в списке сходятся друг от друга: Base, Derived1, Derived2. Я использую XMLArrayItemAttributes для переопределения имен во время сериализации. Это отлично работает в .NET 3.0, но теперь выводит другой результат в .NET 4.0. См. Ниже выходы, отмечая, в частности, второй элемент потомка DerivedItem2.XML-сериализация - отличный результат в .NET 4.0

У кого-нибудь есть опыт работы с этим и как я могу исправить его для работы в .NET 4.0, как это было в версии 3.5?

Кажется, что я не могу контролировать порядок, в котором элементы массива переопределены. Это не похоже на порядок, в котором они добавляются в XMLArrayItems.

Редактирование: Я только что попробовал тот же пример, используя MONO для фреймворков версии 4.0 и 4.5, и он отлично работает с ними. Может ли это быть ошибкой с версиями рамок Microsoft?

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

Выход в исходном (.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> 

выход изменен (.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> 

Update: Выход из .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> 

Обновление: Превращение o n отладочный переключатель в app.config, как показано ниже, ссылается на http://msdn.microsoft.com/en-us/library/aa302290.aspx, я обнаружил, что порядок, в котором применяется Serialization, переопределяет отличие от порядка заполнения массива переопределения. Кто-нибудь знает, как этот порядок определяется или переопределяется?

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

Это дает мне 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

Да, это кажется странным. Вы пробовали с .net 4.5? Согласно моему мнению, порядок, на который проверяется тип 'ai', должен быть только от самого специализированного до наиболее обобщенного типа. Все остальное не имеет смысла, поскольку оно никогда не выдаст правильное имя типа в прилагаемом XML, и поэтому десериализация не будет работать. Вы пытались десериализовать созданный XML? Вы получаете то же поведение, если не переопределяете WriteXml()? – Rory

+0

Может быть какой-то фиктивный аспект для сериализатора, например. вы пытались обеспечить, чтобы ваши производные классы имели метод ReadXml()? – Rory

+0

Спасибо за комментарии Рори. Я пробовал несколько комбинаций включения/исключения ReadXml/WriteXml и, похоже, все же дает одинаковые имена базовых элементов. Также попробовал это с .NET 4.5 как в прежнем режиме, так и без изменений. –

ответ

4

Ну Пат,

я сумел воспроизвести ту же проблему при тестировании кода в. Net4 и, чем изменение на .Net4.5 ...

В .Net4.5 вывод выглядит так же, как и вы, цитируемый для .Net3

Так что просто продолжайте и пропустите .Net4 и вместо этого просто используйте .Net4.5

Причина этой проблемы связана с тем, как объекты построены в памяти в рамках. В .net4 они, вероятно, удерживаются от «базы» до «производных» и в .Net3 и .Net4.5, они удерживаются (вернее, на мой взгляд, и это вопрос мнения) от «производного» до «базового», , Более конкретно, я считаю, что в:

.Net4 Framework хранит экземпляр объекта как тип базы с указателем на производный экземпляр.

.Net4.5/.Net3 структура хранит экземпляр объекта как тип производной с указателями на базовый экземпляр.

В обоих случаях вы получаете тот же результат при работе с объектом в обычных сценариях.

Я помню, как читал, что сбор мусора имел некоторые улучшения в .net4.5, и я считаю, что это всего лишь часть того, что изменили MS-разработчики, чтобы оптимизировать производительность.

В обоих тестах я работал с той же версией XML Serializer (4.0)

+0

G.Y, извините, я не рассматривал этот вопрос какое-то время. Спасибо за информацию. Я довольно уверен, что я протестировал с .NET 4.5 в соответствии с моим комментарием по оригинальному вопросу (12 августа). Я должен вернуться и повторить это. Я скоро вернусь к вам. –

+0

Я только что запустил приложение под .NET 4.5, пожалуйста, просмотрите исходный вопрос с результатом. Хотя это другой результат, он все еще не исправлен. –

Смежные вопросы