在不更改生成的代码的情况下覆盖XmlSerializer中的日期时间解析

时间:2014-09-11 13:52:00

标签: c# xml datetime code-generation xmlserializer

我正在访问第三方API并检索一些XML。我也能够访问xsd,并使用xsd生成用于反序列化的对象,使用XmlSerializer。

XML包含这样的日期:

<modified>2014-08-19T06:39:13.269-0400</modified>

生成的代码如下所示:

    [System.Xml.Serialization.XmlElementAttribute(DataType="time")]
    public System.DateTime modified {
        get {
            return this.modifiedField;
        }
        set {
            this.modifiedField = value;
        }
    }

不幸的是,这会在尝试反序列化时导致错误。

我可以通过用XmlIgnore属性标记它并将这样的代码添加到部分类来解决这个问题:

    [XmlElement("modified")]
    public string modifiedAsString
    {
        get { return this.modified.ToString(); }
        set { this.modified = System.DateTime.Parse(value); }
    }

但是,忽略部分是对生成的类的更改,我必须对所有日期时间进行数百次更改。

我尝试使用MetadataType的东西从外部将属性应用于它,但不幸的是XmlSerializer并没有选择它。

有没有人建议如何在不更改生成的代码或输入XML(我无法控制)的情况下解析它?

1 个答案:

答案 0 :(得分:1)

如果您愿意将System.DateTime更改为自定义包装类,并使用隐式运算符更改为System.DateTime,则可以。虽然我怀疑这可能比忽略的帮助属性更加突破。

您可以创建一个自定义类型,它将包装基础DateTime并执行必要的解析。此外,您可以利用XmlTextAttribute来控制输出以匹配<modified>2014-08-19T06:39:13.269-0400</modified>架构:

public struct CustomDateTime
{
    private DateTime UnderlyingDateTime;

    [XmlText]
    public string CustomFormat
    {
        get { return UnderlyingDateTime.ToString(); }
        set { UnderlyingDateTime = System.DateTime.Parse(value); }
    }

    public static implicit operator DateTime(CustomDateTime custom)
    {
        return custom.UnderlyingDateTime;
    }

    public static implicit operator CustomDateTime(DateTime datetime)
    {
        return new CustomDateTime { UnderlyingDateTime = datetime };
    }
}

这是包含Modified属性的类(你没有提到名称,所以我只称它为Foo):

public class Foo
{
    public CustomDateTime Modified { get; set; }
}

隐式运算符允许您在大多数情况下直接读/写DateTime值:

Foo f = new Foo();
f.Modified = DateTime.Parse("2014-08-19T06:39:13.269-0400");

它支持您的标准耀斑XmlSerializer序列化:

XmlSerializer serializer = new XmlSerializer(typeof(Foo));
var textwriter = new StringWriter();
serializer.Serialize(textwriter, f);

string xml = textwriter.ToString();

Console.WriteLine(xml);

生成的XML(我已经剥离了一些通常位于根节点中的包装垃圾):

<Foo>
  <Modified>2014-08-19 6:39:13 AM</Modified>
</Foo>

反序列化上面的XML:

Foo deserialized = (Foo)serializer.Deserialize(new StringReader(xml));

DateTime datetime = deserialized.Modified;

Console.WriteLine(datetime);

DateTime输出的结果:2014-08-19 6:39:13 AM

现在,这与完全的XML内容不匹配,即显示“2014-08-19 6:39:13 AM”而不是“2014-08-19T06:39: 13.269-0400“,但仅仅是因为我正在跟踪逐字您对DateTime.ToString()财产使用DateTime.Parseget/set

但是,它会很好地读取XML内容,也就是说,如果您的传入XML是:

<Foo>
  <Modified>2014-08-19T06:39:13.269-0400</Modified>
</Foo>

它仍然以相同的方式读取它(基本上它会调用System.DateTime.Parse("2014-08-19T06:39:13.269-0400"))。

编辑:只是为了澄清一下,你必须做出的重大改变就是改变原来的Foo类:

public class Foo
{
    public DateTime Modified { get; set; }
}

对此:

public class Foo
{
    public CustomDateTime Modified { get; set; }
}

如果[System.Xml.Serialization.XmlElementAttribute(DataType="time")]属性的行为在此用法中被正确模拟,我不肯定,但如果不是,则您很容易灵活地实现无论解析您希望在CustomDateTime.CustomFormat属性getter和setter。