2017-08-25 37 views
2

我正在轉換我的工作XML序列化,以便模型類從抽象基類繼承(以允許將來使用不同的串行格式)。如何使用派生類進行XML序列化?

我的序列化按原樣工作正常,但是當我切換到使用從基類派生的模型時,我得到各種異常,所以我不確定如何繼續。

我的階級基礎類是:

namespace Data 
{ 
    public abstract class Configuration 
    { 
     public abstract string Schema { get; set; } 

     public abstract Command[] Commands { get; set; } 
    } 

    public abstract class Command 
    { 
     public abstract string Name { get; set; } 
    } 
} 

我的派生具體類(即工作得很好其所來源前級),然後在子命名空間:

namespace Data.Xml 
{ 
    [Serializable()] 
    [XmlType(AnonymousType = true)] 
    [XmlRoot(Namespace = "", IsNullable = false)] 
    public class Configuration : Data.Configuration 
    { 
     [XmlAttribute("noNamespaceSchemaLocation", 
      Namespace = System.Xml.Schema.XmlSchema.InstanceNamespace)] 
     public override string Schema { get; set; } 

     [XmlArrayItem("Command", IsNullable = false)] 
     public override Data.Command[] Commands { get; set; } 
    } 

    [Serializable()] 
    public class Command : Data.Command 
    { 
     public override string Name { get; set; } 
    } 
} 

我打電話該子名稱空間內的序列化程序如下所示:

public override Data.Configuration DeserializeConfig(StreamReader config) 
{ 
    var cs = new XmlSerializer(typeof(Configuration), 
      new Type[] { typeof(Command) }); 
    return (Configuration)ConfigSerializer.Deserialize(ConfigStreamReader); 
} 

public override string SerializeConfig(Data.Configuration c, Encoding encoding) 
{ 
    string Output = null; 
    var Stream = new MemoryStream(); 
    using (var Writer = new XmlTextWriter(Stream, encoding)) 
    { 
     Writer.Formatting = Formatting.Indented; 
     XmlSerializerNamespaces ns = new XmlSerializerNamespaces(); 
     ns.Add("xsi", XmlSchema.InstanceNamespace); 
     (new XmlSerializer(typeof(Configuration))).Serialize(Writer, c, ns); 
     Output = encoding.GetString(Stream.ToArray()); 
    } 
    Stream.Dispose(); 
    return Output; 
} 

生成的XML應該看起來像:

<?xml version="1.0" encoding="utf-8"?> 
<Configuration 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:noNamespaceSchemaLocation="SomeSchema.xsd"> 
    <Commands> 
    <Command> 
     <Name>SomeNameValue</Name> 
    </Command> 
    </Commands> 
</Configuration> 

我看到當試圖實例化串行器(第一線在上述DeserializeConfig()方法)以下異常:

InvalidOperationException異常:類型 'Data.Command' 和「Data.Xml.Command '都使用命名空間''中的XML類型名稱'Command'。使用XML屬性爲類型指定唯一的XML名稱和/或名稱空間。

我真的不知道爲什麼串行試圖創建從基類的東西,肯定的名稱是相同的,那是一種派生和命名空間等的念頭...... 如何正確用屬性標記它以正確地解除/序列化?

FYI:我沒有看到已經在這幾個問題,但答案似乎都不夠具體,對提問者的要求,我無法工作,如何將信息應用到這一點,看似簡單,場景。

更新:我想通了如何通過包括類型串行化的實例,而不必標註的基類,所以我已刪除的那部分從我的問題,更新的代碼。這超出了布魯諾的建議和我的迴應(儘管建議的問題仍然不適用)。

更新:我試圖通過增加派生類的命名空間(即添加[XmlElement(Namespace = "http://www.foo.com/data/xml")]在派生類中的每個屬性)在XML命名空間的名字分開,但這沒有什麼區別爲串行似乎仍然「看「基礎和派生類都在一起,因此認爲它們都在該名稱空間中。

+0

這是https://stackoverflow.com/questions/3326481/c的重複問題-sharp的XML序列化-的派生類? –

+0

@ bruno.almeida,不,我已經應用了'XmlInclude'屬性。 – Toby

+0

這是你的類名混淆編譯器。網絡庫有System.Net.Data和System.Net.Xml。您正在使用的類名稱正在複製Net庫名稱。所以要麼改變名稱,要麼使用全名,比如MyProject.Data.Xml。 – jdweng

回答

1

最後翻轉計算出大部分這一點。

我退後一步,開始了一個非常簡單的工作非派生示例,並根據需要開展工作。

這裏發生了兩件事。首先是衝突類型名稱,然後是衝突屬性名稱。雖然我有這些權利的每一個權利,排列組合的每個選項的數量混合在一起讓我感到困惑。

爲了防止抽象派生類型名稱在序列化時發生衝突,我需要使派生類類型匿名(這裏使用XmlType屬性)。

要停止的屬性名稱衝突,我需要忽略屬性在派生類中的基類。要做到這一點,而不編輯基類,我錯過了一個重要的部分,XmlAttributeOverrides。我曾在MSDN文檔XmlSerializer.Serialize()中看到過這一點,但是解釋它所涉及的信息非常少。 This answer到另一個問題導致我大衛伍德沃德的excellent explanation

我還沒有嘗試任何與派生類型列表屬性或反序列化。

下面是與控制檯輸出一些序列化的XML輸出一個字符串的程序的完整簡單的例子:

using System; 
using System.Text; 
using System.IO; 
using System.Xml; 
using System.Xml.Serialization; 

namespace Test 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      var TestBar = new MyXml.Bar() 
      { 
       Name = "John Smith", 
      }; 

      Serializer s = new MyXml.Serializer(); 
      var TestOutput = s.Serialize(TestBar); 
      Console.WriteLine(TestOutput); 
     } 
    } 

    public abstract class Bar 
    { 
     public abstract string Name { get; set; } 
    } 

    public abstract class Serializer 
    { 
     public abstract string Serialize(Bar bar); 
    } 

    namespace MyXml 
    { 
     public class Serializer : Test.Serializer 
     { 
      public override string Serialize(Test.Bar bar) 
      { 
       string Output = null; 
       var Stream = new MemoryStream(); 
       var Encoding = new UTF8Encoding(false, true); 

       // Ignore the Name property in the *base* class! 
       var ao = new XmlAttributeOverrides(); 
       var a = new XmlAttributes(); 
       a.XmlElements.Clear(); // Clear any element attributes 
       a.XmlAttribute = null; // Remove any attribute attributes 
       a.XmlIgnore = true; // Set the ignore attribute value true 
       ao.Add(typeof(Test.Bar), "Name", a); // Set to use with Test.Bar.Name 

       using (var Writer = new XmlTextWriter(Stream, Encoding)) 
       { 
        Writer.Formatting = Formatting.Indented; 
        var s = new XmlSerializer(typeof(Bar), ao); 
        s.Serialize(Writer, bar); 
        Output = Encoding.GetString(Stream.ToArray()); 
       } 
       Stream.Dispose(); 
       return Output; 
      } 
     } 

     [Serializable] 
     [XmlType(AnonymousType = true)] // Make type anonymous! 
     [XmlRoot(IsNullable = false)] 
     public class Bar : Test.Bar 
     { 
      [XmlIgnore] // Ignore the Name property in the *derived* class! 
      public override string Name 
      { 
       get => Unreverse(ReverseName); 
       set => ReverseName = Reverse(value); 
      } 

      [XmlElement("Name", IsNullable = false)] 
      public string ReverseName { get; set; } 

      private string Unreverse(string name) 
      { 
       return "John Smith"; // Smith, John -> John Smith 
      } 

      private string Reverse(string name) 
      { 
       return "Smith, John"; // John Smith -> Smith, John 
      } 
     } 
    } 
} 
+1

我有一個簡單的類模型,從另一個繼承並得到「兩個在xml序列化時使用XML類型名稱「錯誤。將「[XmlType(AnonymousType = true)]」添加到繼承的類中解決了問題。 – Vlad