1

I have a class which I use the XmlSerializer with to serialize data to and from XML files.

I have several DateTime properties. In the post, Prevent timezone conversion on deserialization of DateTime value the answer correctly removes timezone offsets from DateTime properties.

However, I have a property which is a list of DateTime objects that I can't remove the timezones from.

[XmlElement]
public List<DateTime> Times {get; set;}

I have tired something like this, but the value is always null and none of the data is correctly serialized to the list property.

[XmlIgnore]
public List<DateTime> Times {get; set;}

[XmlElement(ElementName = "Times")]
public List<string> TimesString
{
 get
 {
   return Times.ForEach(fe => RemoveTimeZone(fe));
 }
 set
 {
   foreach(var v in value)
   {
     Times.Add(ConvertToDate(v));
   }
 }


}

The value property is always empty and both list properties are always empty.

My goal is to not create a new class, but to somehow bind directly to my list properties.

Community
  • 1
  • 1
FBTH
  • 13
  • 2

1 Answers1

0

Your TimesString property is a proxy collection property, i.e. a property that gets or sets an underlying collection, transforming its members in the process. The simplest way to make such a proxy collection work correctly with XmlSerializer is to make it be an array rather than a list, in your case a string []:

    [XmlIgnore]
    public List<DateTime> Times { get; set; }

    [XmlElement(ElementName = "Times")]
    public string [] TimesString
    {
        get
        {
            return Times == null ? null : Times.Select(t => RemoveTimeZone(t)).ToArray();
        }
        set
        {
            if (value == null)
                return;
            (Times = Times ?? new List<DateTime>(value.Length)).AddRange(value.Select(s => ConvertToDate(s)));
        }
    }

string [] works while List<string> does not because XmlSerializer deserializes a property referring to a class implementing IList<T> in the following way:

  1. It calls the getter to get the list. If null, it allocates a list and sets it via the setter. It holds onto the list in some local variable while populating it.

  2. It deserializes each list element, and adds it to the list it is holding.

  3. And that's it. It never calls the containing class's list property setter afterwards.

However, since an array is basically a read-only collection and so cannot be added to once allocated, it cannot be set back until completely populated. This is what XmlSerializer does, which allows proxy array properties to deserialized successfully.

For more, see Cannot deserialize XML into a list using XML Deserializer or XML Deserialization of collection property with code defaults.

dbc
  • 104,963
  • 20
  • 228
  • 340