在c#中,封送和取消封送DateTime.MinValue的结果很奇怪

本文关键字:结果 MinValue 取消 DateTime | 更新日期: 2023-09-27 18:00:04

以下是代码:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 4)]
public class STTEST
{
    public DateTime DateTime;
}
static void Main(string[] args)
{
   var st0 = new STTEST();
   var bs0 = st0.ToBytes();
   var st1 = bs0.ToObject<STTEST>();
}

助手代码:

public static byte[] ToBytes(this object obj)
{           
     int size = Marshal.SizeOf(obj);             
     byte[] bytes = new byte[size];               
     IntPtr structPtr = Marshal.AllocHGlobal(size);               
     Marshal.StructureToPtr(obj, structPtr, false);               
     Marshal.Copy(structPtr, bytes, 0, size);               
     Marshal.FreeHGlobal(structPtr);              
     return bytes;          
 }
 public static T ToObject<T>(this byte[] bytes)
 {
        int size = Marshal.SizeOf(typeof(T));           
        IntPtr structPtr = Marshal.AllocHGlobal(size);
        Marshal.Copy(bytes, 0, structPtr, size);
        object obj = Marshal.PtrToStructure(structPtr, typeof(T));
        Marshal.FreeHGlobal(structPtr);
        return (T)obj;
 }

封送处理操作正确,字节的内容为零。但取消封送处理操作返回st1.DateTime为"1899/12/30"。应该是"0001/01/01"!怎么了?:-(

在c#中,封送和取消封送DateTime.MinValue的结果很奇怪

Marshal.PtrToStructure()旨在将结构的内容转换为本机代码能够理解的表示形式。没有任何本机代码知道DateTime可能是什么样子。有多种"标准",本机代码倾向于使用Unix时间戳(自1970年1月1日起的秒数)或FILETIME(自1600年1月起的100纳秒)或COM自动化日期(自1899年12月30日起的浮点天数)。

由于被迫在这些不兼容的标准之间做出选择,CLR设计者选择了互操作代码中最常见的表示形式,即COM标准。也公开为DateTime.To/FromOADate()。由于未初始化DateTime,它被迫转换为DATE的最低合法值,即浮点值0。因此,转换回1899年12月30日。

使用pinvokemarshaller将对象序列化为字节是一个不确定的命题,对于像这样的意外结果,可能性为零。如果不让DateTime未初始化,您可能会有所进步。