元帅.StructureToPtr & lt;→PtrToStructure轮询DateTime字段

本文关键字:PtrToStructure 轮询 DateTime 字段 StructureToPtr lt 元帅 | 更新日期: 2023-09-27 18:01:41

结构
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在编组后四舍五入?这在什么地方有记录吗?

元帅.StructureToPtr & lt;→PtrToStructure轮询DateTime字段

marshal . structuretoptr()用于封送非托管代码的数据。本机代码中的日期有多个"标准",没有一个在范围和精度上接近DateTime。CLR设计者选择了COM互操作标准,也由DateTime.ToOADate()公开。

从参考源中可以看出,它不能比1毫秒更精确。DateTime精确到0.1秒。不可避免地,你所看到的最后四位数字必须是0。

不清楚你为什么要这样做,或者为什么它很重要。请记住,Marshal.StructureToPtr()仅似乎是序列化。net数据的一种有吸引力的方式。

真正的错误是DateTime不应该是可编组的…如果你直接尝试Marshal,你会得到一个ArgumentException

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

public long date;
public DateTime Date
{
    get
    {
        return DateTime.FromBinary(date);
    }
    set
    {
        date = value.ToBinary();
    }
}