Как использовать XmlAttributeOverrides при сериализации массива? - PullRequest
6 голосов
/ 11 февраля 2010

У меня есть массив с именем _updatedComponents объектов класса NetworkComponent. Я должен сериализовать его так, чтобы имя и пространство имен корневого элемента (= массив) были изменены, а имя отдельного элемента NetworkComponent было изменено на компонент. У меня есть код ниже, который вызывает исключение:

System.InvalidOperationException: произошла ошибка, отражающая тип 'ComponentSyncService.NetworkComponent []'. ---> System.InvalidOperationException: атрибуты XmlRoot и XmlType нельзя указывать для типа ComponentSyncService.NetworkComponent [].

Код:

XmlAttributeOverrides xaos = new XmlAttributeOverrides();

// the array itself aka the root. change name and namespace
XmlElementAttribute xea = new XmlElementAttribute(_updatedComponents.GetType());
xea.Namespace = "http://www.example.com/nis/componentsync";
xea.ElementName = "components";

XmlAttributes xas = new XmlAttributes();
xas.XmlElements.Add(xea);
xaos.Add(_updatedComponents.GetType(), xas); 

// then the items of the array. just change the name
xea = new XmlElementAttribute(typeof(networkcomponent));
xea.ElementName = "component";

xas = new XmlAttributes();
xas.XmlElements.Add(xea);
xaos.Add(typeof(NetworkComponent), "NetworkComponent", xas);

XmlSerializer serializer = new XmlSerializer(_updatedComponents.GetType(), xaos);

XmlTextWriter writer = new XmlTextWriter(string.Format("{0}\\ComponentSyncWS_{1}.xml", 
                      Preferences.FileSyncDirectory, requestId), Encoding.UTF8);
serializer.Serialize(writer, _updatedComponents);

1 Ответ

8 голосов
/ 11 февраля 2010

Что такое _updatedComponents? Я предполагаю, что это NetworkComponent[] - что сделает все очень сложно. Я бы предложил написать обертку типа:

public class ComponentsMessage {
    public NetworkComponent[] Components {get;set;}
}

Тогда вы можете связать правильные атрибуты. Если вам нужно поддерживать специальные атрибуты на NetworkComponent, вам все равно придется использовать переопределения атрибутов (поэтому я вообще не украшал вышеприведенное), но ComponentsMessage должен быть рад принять атрибуты. *

Либо просто напишите отдельный DTO и отобразите значения.

Если это просто, вы можете просто использовать:

[XmlRoot("components", Namespace = XmlNamespace)]
[XmlType("components", Namespace = XmlNamespace)]
public class ComponentsMessage
{
    public const string XmlNamespace = "http://www.example.com/nis/componentsync";
    [XmlElement("component")]
    public NetworkComponent[] Components { get; set; }
}

В качестве альтернативы, если вы должны использовать переопределения атрибутов, я все равно использовал бы объект-оболочку:

public class ComponentsMessage
{
    public NetworkComponent[] Components { get; set; }
}
class Program
{
    static void Main()
    {
        NetworkComponent[] _updatedComponents = new NetworkComponent[2] {
            new NetworkComponent{},new NetworkComponent{}
        };
        const string XmlNamespace = "http://www.example.com/nis/componentsync";
        XmlAttributeOverrides ao = new XmlAttributeOverrides();
        ao.Add(typeof(ComponentsMessage), new XmlAttributes {
            XmlRoot = new XmlRootAttribute("components") { Namespace = XmlNamespace },
            XmlType = new XmlTypeAttribute("components") { Namespace = XmlNamespace }
        });
        ao.Add(typeof(ComponentsMessage), "Components", new XmlAttributes {
            XmlElements =  {
                new XmlElementAttribute("component")
            }
        });
        ComponentsMessage msg = new ComponentsMessage { Components = _updatedComponents };
        XmlSerializer serializer = new XmlSerializer(msg.GetType(), ao);
        serializer.Serialize(Console.Out, msg);
    }
}
...