2015-10-07 3 views
2

В настоящее время я пытаюсь настроить некоторые команды как классы для сериализации для протокола связи. Мой код в основном следующим образом:C# XML Сериализация с абстрактным классом

[XmlRoot("Message")] 
[Serializable] 
public class Message 
{ 
    private Command[] _commands; 

    [XmlAttribute("ver")] 
    public int Version { get; set; } 
    [XmlAttribute("msid")] 
    public Guid Id { get; set; } 

    [XmlArray("Commands")] 
    [XmlArrayItem(typeof(HealthCheckCommand))] 
    [XmlArrayItem(typeof(TestCommand))] 
    public Command[] Commands 
    { 
     get { return _commands; } 
     set { _commands = value; } 
    } 
} 

public enum CommandTypes 
{ 
    healthcheck 
} 

[XmlType(TypeName = "Command")] 
public abstract class Command 
{ 
    String CommandType { get; set; } 
} 

public class HealthCheckCommand : Command 
{ 
    [XmlAttribute("type")] 
    public string CommandType 
    { 
     get { return "healthcheck"; } 
     set { throw new NotImplementedException(); } 
    } 
} 

public class TestCommand : Command 
{ 
    [XmlAttribute("type")] 
    public string CommandType 
    { 
     get { return "test"; } 
     set { throw new NotImplementedException(); } 
    } 
} 

Что мне нужно, чтобы получить от этого:

<Message ver="1" msid="00000000-0000-0000-0000-000000000000"> 
    <Commands> 
    <Command type="healthcheck" /> 
    <Command type="test" /> 
    </Commands> 
</Message> 

Что я получаю это:

<Message ver="1" msid="00000000-0000-0000-0000-000000000000"> 
    <Commands> 
    <HealthCheckCommand type="healthcheck" /> 
    <TestCommand type="test" /> 
    </Commands> 
</CTM> 

При попытке переопределить Имя XmlArrayItem с тем же именем, конечно же, вызывает ошибку. Если я использую список, то он работает, но я получаю все элементы пространства имен внутри подтипов, чего я не хочу. Я мог бы пойти и удалить эти элементы пространства имен после факта, но я бы предпочел не. Должен быть способ сделать это.

Спасибо за помощь!

EDIT:

Вот код сериализации:

XmlSerializer serializer = new XmlSerializer(typeof (Message)); 
     using (TextWriter writer = new StreamWriter(@"C:\Xml.txt")) 
     { 
      XmlSerializerNamespaces xmlSerializerNamespaces = new XmlSerializerNamespaces(); 
      xmlSerializerNamespaces.Add("", ""); 
      XmlWriterSettings settings = new XmlWriterSettings(); 
      settings.OmitXmlDeclaration = true; 

      using (
      XmlWriter xmlwriter = XmlWriter.Create(writer, new XmlWriterSettings { OmitXmlDeclaration = true })) 
      { 
       serializer.Serialize(xmlwriter, message, xmlSerializerNamespaces); 
      } 
     } 
    } 
+0

Возможный дубликат [Наследственное XMLType базового класса] (http://stackoverflow.com/questions/26128732/inherit-xmltype-of-base-class) –

ответ

0

Включить производные типы путем добавления соответствующих XmlInclude атрибутов на Message:

[XmlInclude(typeof(HealthCheckCommand))] 
[XmlInclude(typeof(TestCommand))] 

Затем укажите имя элемента для вашего Command[] элементы массива:

[XmlArrayItem("Command")] 

Это создает XML, как это, что, вероятно, то же самое, когда вы использовали List:

<Message xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" ver="0" msid="00000000-0000-0000-0000-000000000000"> 
    <Commands> 
     <Command xsi:type="HealthCheckCommand" type="healthcheck" /> 
     <Command xsi:type="TestCommand" type="test" /> 
    </Commands> 
</Message> 

К сожалению xsi:type атрибуты необходимы для того, чтобы десериализация работать (иначе как бы serialiser знать, какие типы использовать?). Однако их можно легко удалить после факта. Разобрать XML с XDocument и удалить их, как так:

XNamespace xsi = "http://www.w3.org/2001/XMLSchema-instance"; 

doc.Descendants() 
    .Attributes(xsi + "type") 
    .Remove(); 

doc.Descendants() 
    .Attributes() 
    .Where(a => a.IsNamespaceDeclaration && a.Value == xsi) 
    .Remove(); 
+0

Мои подкоманды имеют p3: type = "testcommand", а не xsi: type и у них есть свои собственные xmlns ... как удалить sub xmlns? – Giallo

+0

У вас будет добавленный код, который вы используете для сериализации, поскольку это не тот результат, который я получаю. При догаде вы передаете «XmlSerializerNamespaces» в сериализатор? –

+0

Я добавил код сериализации. Не могли бы вы добавить свои? Благодаря! – Giallo

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