.NET XML serialization gotchas? [closed]

2020-01-23 13:36发布

I've run into a few gotchas when doing C# XML serialization that I thought I'd share:


using System;
using System.Collections.Generic;
using System.Text;
using System.Xml.Serialization;

[XmlRoot("dictionary")]
public class SerializableDictionary<TKey, TValue> : Dictionary<TKey, TValue>, IXmlSerializable
{      
    public System.Xml.Schema.XmlSchema GetSchema()
    {
        return null;
    }

    public void ReadXml(System.Xml.XmlReader reader)
    {
        XmlSerializer keySerializer = new XmlSerializer(typeof(TKey));
        XmlSerializer valueSerializer = new XmlSerializer(typeof(TValue));

        bool wasEmpty = reader.IsEmptyElement;
        reader.Read();

        if (wasEmpty)
            return;

        while (reader.NodeType != System.Xml.XmlNodeType.EndElement)
        {
            reader.ReadStartElement("item");

            reader.ReadStartElement("key");
            TKey key = (TKey)keySerializer.Deserialize(reader);
            reader.ReadEndElement();

            reader.ReadStartElement("value");
            TValue value = (TValue)valueSerializer.Deserialize(reader);
            reader.ReadEndElement();

            this.Add(key, value);

            reader.ReadEndElement();
            reader.MoveToContent();
        }
        reader.ReadEndElement();
    }

    public void WriteXml(System.Xml.XmlWriter writer)
    {
        XmlSerializer keySerializer = new XmlSerializer(typeof(TKey));
        XmlSerializer valueSerializer = new XmlSerializer(typeof(TValue));

        foreach (TKey key in this.Keys)
        {
            writer.WriteStartElement("item");

            writer.WriteStartElement("key");
            keySerializer.Serialize(writer, key);
            writer.WriteEndElement();

            writer.WriteStartElement("value");
            TValue value = this[key];
            valueSerializer.Serialize(writer, value);
            writer.WriteEndElement();

            writer.WriteEndElement();
        }
    }
}

Any other XML Serialization gotchas out there?

19条回答
别忘想泡老子
2楼-- · 2020-01-23 13:38

If you try to serialize an array, List<T>, or IEnumerable<T> which contains instances of subclasses of T, you need to use the XmlArrayItemAttribute to list all the subtypes being used. Otherwise you will get an unhelpful System.InvalidOperationException at runtime when you serialize.

Here is part of a full example from the documentation

public class Group
{  
   /* The XmlArrayItemAttribute allows the XmlSerializer to insert both the base 
      type (Employee) and derived type (Manager) into serialized arrays. */

   [XmlArrayItem(typeof(Manager)), XmlArrayItem(typeof(Employee))]
   public Employee[] Employees;
查看更多
你好瞎i
3楼-- · 2020-01-23 13:40

Properties marked with the Obsolete attribute aren't serialized. I haven't tested with Deprecated attribute but I assume it would act the same way.

查看更多
Root(大扎)
4楼-- · 2020-01-23 13:44

Private variables/properties are not serialized in XML serialization, but are in binary serialization.

I believe this also gets you if you are exposing the private members through public properties - the private members don't get serialised so the public members are all referencing null values.

查看更多
▲ chillily
5楼-- · 2020-01-23 13:45

Can't serialize an object which doesn't have a parameterless construtor (just got bitten by that one).

And for some reason, from the following properties, Value gets serialised, but not FullName:

    public string FullName { get; set; }
    public double Value { get; set; }

I never got round to working out why, I just changed Value to internal...

查看更多
混吃等死
6楼-- · 2020-01-23 13:49

If the serializer encounters a member/property that has an interface as its type, it won't serialize. For example, the following won't serialize to XML:

public class ValuePair
{
    public ICompareable Value1 { get; set; }
    public ICompareable Value2 { get; set; }
}

Though this will serialize:

public class ValuePair
{
    public object Value1 { get; set; }
    public object Value2 { get; set; }
}
查看更多
虎瘦雄心在
7楼-- · 2020-01-23 13:49

One more thing to note: you can't serialize private/protected class members if you are using the "default" XML serialization.

But you can specify custom XML serialization logic implementing IXmlSerializable in your class and serialize any private fields you need/want.

http://msdn.microsoft.com/en-us/library/system.xml.serialization.ixmlserializable.aspx

查看更多
登录 后发表回答