Marshal.StructureToPtr <-> PtrToStructure 舍入 DateTime 字段
Marshal.StructureToPtr <-> PtrToStructure rounds DateTime field
结构
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 在编组后四舍五入?这在某处记录了吗?
真正的错误是 DateTime
不应该编组...如果您尝试直接 Marshal
它,您会得到一个 ArgumentException
.
如果您真的想要 Marshal
一个 DateTime
(考虑到它是 .NET 的半专有格式,我什至不想知道为什么),您可以:
public long date;
public DateTime Date
{
get
{
return DateTime.FromBinary(date);
}
set
{
date = value.ToBinary();
}
}
Marshal.StructureToPtr() 旨在为非托管代码编组数据。本机代码中有多个日期 "standards",none 在范围和精度上接近 DateTime。 CLR 设计者选择了 COM 互操作标准,也由 DateTime.ToOADate().
公开
从Reference Source可以看出,它不能比1毫秒更准确。 DateTime 精确到 0.1 微秒。不可避免地,您正在查看的最后 4 位数字必须为 0。
不清楚您为什么要这样做或为什么它很重要。猜测,请记住 Marshal.StructureToPtr() 只是 似乎 是序列化 .NET 数据的一种有吸引力的方式。
结构
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 在编组后四舍五入?这在某处记录了吗?
真正的错误是 DateTime
不应该编组...如果您尝试直接 Marshal
它,您会得到一个 ArgumentException
.
如果您真的想要 Marshal
一个 DateTime
(考虑到它是 .NET 的半专有格式,我什至不想知道为什么),您可以:
public long date;
public DateTime Date
{
get
{
return DateTime.FromBinary(date);
}
set
{
date = value.ToBinary();
}
}
Marshal.StructureToPtr() 旨在为非托管代码编组数据。本机代码中有多个日期 "standards",none 在范围和精度上接近 DateTime。 CLR 设计者选择了 COM 互操作标准,也由 DateTime.ToOADate().
公开从Reference Source可以看出,它不能比1毫秒更准确。 DateTime 精确到 0.1 微秒。不可避免地,您正在查看的最后 4 位数字必须为 0。
不清楚您为什么要这样做或为什么它很重要。猜测,请记住 Marshal.StructureToPtr() 只是 似乎 是序列化 .NET 数据的一种有吸引力的方式。