C#XmlSerializer-通用自定义适配器,用于处理无效的AllXsd值(例如Java的XmlJavaTypeAdapter)

时间:2018-10-08 12:22:55

标签: c# xml datetime adapter xmlserializer

我使用许多可序列化的对象反序列化xml。 我读过,为了避免DateTime中的AllXsd值无效,我必须创建一个辅助字符串属性,该属性会将输入作为字符串进行处理并将其转换。 即

[XmlIgnore]
public DateTime? DateUpdated { get; set; }

[XmlElement("updateDate")]
public string DateUpdatedAsText
{
    set
    {
        if (!string.IsNullOrWhiteSpace(value))
        {
            try
            {
                DateUpdated = DateTime.Parse(value, CultureInfo.InvariantCulture);
            }
            catch (Exception) { }
        }
    }
    get
    {
        return DateUpdated.HasValue ? DateUpdated.Value.ToString("yyyy-MM-ddTHH:mm:ss") : null;
    }
}

这已经过测试,效果很好。但是...

我有100多个实体,其中包含DateTime字段,其中一些实体不止一个,并且这种解决方案不是很实用。我将必须在所有这些工具中实施此操作,如果将来我想更改任何内容,则必须在所有这些工具中再次执行。 我如何声明一个通用的自定义适配器来处理所有DateTime类型。在Java中,我可以这样做:

@XmlJavaTypeAdapter(CalendarXmlAdapter.class)
@Column(name = "updateDate")
private Calendar DateUpdated;

并在CalendarXmlAdapter.class中指定编组和解编

C#System.Xml.Serialization.XmlSerializer是否有类似的解决方案?

预先感谢

已编辑

解决方案: 它是@dbc注释和@ steve16351答案的组合。我使用了CustomDateTime类(对ReadXml进行了一些小的更改,但并不重要),并且在字段SomeDate的声明中(仍为DateTime?类型),我像这样使用它

    [XmlElement(ElementName = "updateDate", IsNullable = true, Type = typeof(CustomDateTime))]
    public DateTime? DateUpdated { get; set; }

转换顺利进行

1 个答案:

答案 0 :(得分:1)

如果需要对反序列化进行更多控制,则可以使用IXmlSerializable。据我所知,虽然您无法为XmlSerializer的特定类型全局提供自定义转换器,但是您可以像下面的实现DateTime一样编写一个代理IXmlSerializable类,我认为这更优雅比您拥有的字符串属性和相应的DateTime属性的解决方案;并会减少对代码库的破坏。

这里是这种解决方案的一个例子。它还利用隐式运算符来避免需要在您自己的代码中与DateTime?之间进行转换。

class Program
{
    static void Main(string[] args)
    {
        XmlSerializer s = new XmlSerializer(typeof(MyClass));
        MyClass myClass = null;
        using (var sr = new StringReader(@"<myXml><updateDate>20181008</updateDate><someProp>Hello, world</someProp></myXml>"))            
            myClass = s.Deserialize(sr) as MyClass;            

        DateTime? myValue = myClass.SomeDate;
        Console.WriteLine($"{myClass.SomeDate}");
        Console.ReadKey();
    }
}

[XmlRoot("myXml")]
public class MyClass
{
    [XmlElement("updateDate")]
    public CustomDateTime SomeDate { get; set; }
    [XmlElement("someProp")]
    public string SomeProp { get; set; }

}

public class CustomDateTime : IXmlSerializable
{
    public DateTime? _dateTime { get; set; }
    private const string EXPECTED_FORMAT = "yyyyMMdd";

    public XmlSchema GetSchema()
    {
        throw new NotImplementedException();
    }

    public void ReadXml(XmlReader reader)
    {
        var elementContent = reader.ReadElementContentAsString();
        _dateTime = String.IsNullOrWhiteSpace(elementContent) ? (DateTime?)null : DateTime.ParseExact(elementContent, EXPECTED_FORMAT, CultureInfo.InvariantCulture);
    }

    public void WriteXml(XmlWriter writer)
    {
        if (!_dateTime.HasValue) return;
        writer.WriteString(_dateTime.Value.ToString(EXPECTED_FORMAT));
    }

    public static implicit operator DateTime? (CustomDateTime input)
    {
        return input._dateTime;
    }

    public static implicit operator CustomDateTime (DateTime input)
    {
        return new CustomDateTime() { _dateTime = input };
    }

    public override string ToString()
    {
        if (_dateTime == null) return null;
        return _dateTime.Value.ToString();
    }
}