Marshal.StructureToPtr< - > PtrToStructure舍入DateTime字段

时间:2015-07-08 12:58:41

标签: c# .net marshalling

结构

public struct Tick : IEquatable<Tick>
{
    public DateTime date;
    public decimal price;
    public int volume;

    public Tick(DateTime date, decimal price, int volume)
    {
        this.date = date;
        this.price = price;
        this.volume = volume;
    }

    public override bool Equals(object obj)
    {
        var other = (Tick)obj;
        return this.date == other.date && this.price == other.price && this.volume == other.volume;
    }
    public bool Equals(Tick other)
    {
        return this.date == other.date && this.price == other.price && this.volume == other.volume;
    }
}

在此测试中已更改:

    [Test]
    public void MarshalDoesntRoundsDateTime() {
        for (int i = 0; i < 1000; i++)
        {
            var now = new Tick(DateTime.Now.AddSeconds(i), i, i);
            var now2 = now;

            var ticks = new Tick[1];
            unsafe
            {
                fixed (Tick* ptr = &ticks[0])
                {
                    Marshal.StructureToPtr(now2, (IntPtr)ptr, false);
                    now2 = (Tick)Marshal.PtrToStructure((IntPtr)ptr, typeof(Tick));
                    Assert.AreEqual(now.date.Ticks, now2.date.Ticks);
                }
            }
        }
    }


  Expected: 635719676058860752
  But was:  635719676058860000

发生了什么事?编组后为什么DateTime会被舍入?这是在某处记录的吗?

2 个答案:

答案 0 :(得分:2)

Marshal.StructureToPtr()旨在封送非托管代码的数据。本机代码中的日期有多个“标准”,没有一个与DateTime的范围和准确性接近。 CLR设计者采用了COM互操作标准,也是由DateTime.ToOADate()公开的。

Reference Source可以看出,它可能不会超过1毫秒。 DateTime精确到0.1 usec。您正在查看的最后4位数字不可避免地必须为0.

目前尚不清楚为什么要这样做或者为什么重要。猜测,请记住Marshal.StructureToPtr()只有似乎就像序列化.NET数据一样有吸引力。

答案 1 :(得分:1)

真正的错误是DateTime不应该被编组...如果您尝试Marshal直接获得ArgumentException

如果你真的想要Marshal DateTime(我甚至不想知道为什么,考虑到它是.NET的半专有格式),你可以:

public long date;

public DateTime Date
{
    get
    {
        return DateTime.FromBinary(date);
    }

    set
    {
        date = value.ToBinary();
    }
}