我如何XML序列化DateTimeOffset属性?

Pur*_*ome 21 .net xml-serialization

DateTimeOffset当数据表示为Xml时,我在此类中拥有的属性不会被呈现.我需要做什么来告诉Xml序列化将其正确呈现为DateTimeDateTimeOffset

[XmlRoot("playersConnected")]
public class PlayersConnectedViewData
{
    [XmlElement("playerConnected")]
    public PlayersConnectedItem[] playersConnected { get; set; }
}

[XmlRoot("playersConnected")]
public class PlayersConnectedItem
{
    public string name { get; set; }
    public DateTimeOffset connectedOn { get; set; }  // <-- This property fails.
    public string server { get; set; }
    public string gameType { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

和一些样本数据......

<?xml version="1.0" encoding="utf-8"?>
<playersConnected 
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <playerConnected>
    <name>jollyroger1000</name>
    <connectedOn />
    <server>log1</server>
    <gameType>Battlefield 2</gameType>
  </playerConnected>
</playersConnected>
Run Code Online (Sandbox Code Playgroud)

更新

我希望可能有一种方法通过属性,我可以在属性上装饰......

奖金问题

有没有办法摆脱根节点中声明的那两个命名空间?我是不是该?

Pet*_*ter 26

这是晚了几年,但这是使用ISO 8601 完全序列化的快速简便方法DateTimeOffset:

[XmlElement("lastUpdatedTime")]
public string lastUpdatedTimeForXml // format: 2011-11-11T15:05:46.4733406+01:00
{
   get { return lastUpdatedTime.ToString("o"); } // o = yyyy-MM-ddTHH:mm:ss.fffffffzzz
   set { lastUpdatedTime = DateTimeOffset.Parse(value); } 
}
[XmlIgnore] 
public DateTimeOffset lastUpdatedTime;
Run Code Online (Sandbox Code Playgroud)

  • 与 XmlConvert.ToString(DateTimeOffset) 相同,并且 XmlConvert.ToDateTimeOffset(String) 更干净。但过了一段时间后,为要使用的每个全球化日期类型添加如此多的属性就会变得乏味。因此,对于大量使用,我觉得在这种情况下,创建一个实现 IXmlSerialized 加上 IConvertable 和赋值运算符的新结构可能会更好。 (2认同)

And*_*Dog 14

我想出了这个结构,它实现了基于ISO 8601格式化的XML序列化(例如2011-11-11T15:05:46.4733406+01:00).提示:尝试按预期解析失败DateTime等值2011-11-11T15:05:46.

欢迎反馈.我没有在这里包含单元测试,因为那将是太多的文本.

/// <remarks>
/// The default value is <c>DateTimeOffset.MinValue</c>. This is a value
/// type and has the same hash code as <c>DateTimeOffset</c>! Implicit
/// assignment from <c>DateTime</c> is neither implemented nor desirable!
/// </remarks>
public struct Iso8601SerializableDateTimeOffset : IXmlSerializable
{
    private DateTimeOffset value;

    public Iso8601SerializableDateTimeOffset(DateTimeOffset value)
    {
        this.value = value;
    }

    public static implicit operator Iso8601SerializableDateTimeOffset(DateTimeOffset value)
    {
        return new Iso8601SerializableDateTimeOffset(value);
    }

    public static implicit operator DateTimeOffset(Iso8601SerializableDateTimeOffset instance)
    {
        return instance.value;
    }

    public static bool operator ==(Iso8601SerializableDateTimeOffset a, Iso8601SerializableDateTimeOffset b)
    {
        return a.value == b.value;
    }

    public static bool operator !=(Iso8601SerializableDateTimeOffset a, Iso8601SerializableDateTimeOffset b)
    {
        return a.value != b.value;
    }

    public static bool operator <(Iso8601SerializableDateTimeOffset a, Iso8601SerializableDateTimeOffset b)
    {
        return a.value < b.value;
    }

    public static bool operator >(Iso8601SerializableDateTimeOffset a, Iso8601SerializableDateTimeOffset b)
    {
        return a.value > b.value;
    }

    public override bool Equals(object o)
    {
        if(o is Iso8601SerializableDateTimeOffset)
            return value.Equals(((Iso8601SerializableDateTimeOffset)o).value);
        else if(o is DateTimeOffset)
            return value.Equals((DateTimeOffset)o);
        else
            return false;
    }

    public override int GetHashCode()
    {
        return value.GetHashCode();
    }

    public XmlSchema GetSchema()
    {
        return null;
    }

    public void ReadXml(XmlReader reader)
    {
        var text = reader.ReadElementString();
        value = DateTimeOffset.ParseExact(text, format: "o", formatProvider: null);
    }

    public override string ToString()
    {
        return value.ToString(format: "o");
    }

    public string ToString(string format)
    {
        return value.ToString(format);
    }

    public void WriteXml(XmlWriter writer)
    {
        writer.WriteString(value.ToString(format: "o"));
    }
}
Run Code Online (Sandbox Code Playgroud)


小智 5

我也不确定最好的方法,但这就是我做的:

[XmlElement("lastUpdatedTime")]
public string lastUpdatedTimeForXml
{
  get { return lastUpdatedTime.ToString(); }
  set { lastUpdatedTime = DateTimeOffset.Parse(value); }
}
[XmlIgnore] 
public DateTimeOffset lastUpdatedTime;
Run Code Online (Sandbox Code Playgroud)

  • 我认为你的getter应该是:get {return lastUpdatedTime.ToString("o"); }.这将以XML日期/时间格式返回字符串. (2认同)

Pur*_*ome 2

我最终只是这样做了......

添加了两个扩展方法...

public static double ToUnixEpoch(this DateTimeOffset value)
{
    // Create Timespan by subtracting the value provided from 
    //the Unix Epoch then return the total seconds (which is a UNIX timestamp)
    return (double)((value - new DateTime(1970, 1, 1, 0, 0, 0, 0)
        .ToLocalTime())).TotalSeconds;
}

public static string ToJsonString(this DateTimeOffset value)
{
    return string.Format("\\/Date({0})\\/", value.ToUnixEpoch());
}
Run Code Online (Sandbox Code Playgroud)

修改了ViewData类...

[XmlRoot("playersConnected")]
public class PlayersConnectedItem
{
    public string name { get; set; }
    public string connectedOn { get; set; }
    public string server { get; set; }
    public string gameType { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

更改了我设置 viewdata 属性的方式...

var data = (from q in connectedPlayerLogEntries
            select new PlayersConnectedItem
                       {
                           name = q.ClientName,
                           connectedOn =  q.CreatedOn.ToJsonString(),
                           server = q.GameFile.UniqueName,
                           gameType = q.GameFile.GameType.Description()
                        });
Run Code Online (Sandbox Code Playgroud)

完毕。不确定这是否是最好的方法..但现在 viewdata 属性对于 Json 或 Xml 具有相同的值。