编组和取消编组DateTime.MinValue的结果在c#中很奇怪

时间:2015-06-28 11:51:59

标签: c# datetime marshalling

以下是代码:

trait EntityState
trait Transient extends EntityState
trait Persistent extends EntityState
trait Entity[State <: EntityState] {
  def id(implicit ev: State <:< Persistent): Long
  def persist(implicit ev: State <:< Transient): Entity[Persistent]
}

class Post[State <: EntityState] extends Entity[State] {
  override def id(implicit ev: <:<[State, Persistent]): Long = 5
  override def persist(implicit ev: <:<[State, Transient]): Post[Persistent] = new Post[Persistent]
}

// compiles
val x: Post[Persistent] = (new Post[Transient]).persist
// doesn't compile, as desired
// val y = (new Post[Persistent]).persist

助手代码:

[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>();
}

编组操作正确,字节内容为零。 但是,编组操作返回st1.DateTime是“1899/12/30”。它应该是“0001/01/01”! 这是怎么回事? : - (

1 个答案:

答案 0 :(得分:2)

Marshal.PtrToStructure()意图将结构内容转换为本机代码可以理解的表示形式。没有任何本机代码可以了解DateTime的外观。有多个“标准”,本机代码倾向于使用Unix时间戳(自1970年1月1日以来的秒数)或FILETIME(自1/1/1600以来100纳秒)或COM自动化日期(自12/30以来的浮动天数) / 1899)。

由于被迫在这些不兼容的标准之间做出选择,CLR设计人员在互操作代码(COM标准)中寻求最常见的表示。也显示为DateTime.To/FromOADate()。由于您未将DateTime保留为未初始化,因此它被强制转换为DATE的最低合法值,浮点值为0.因此转换为12/30/1899。

使用pinvoke marshaller将对象序列化为字节是一个iffy命题,对于像这样的意外结果具有非零赔率。你可能会因为没有让DateTime未初始化而在某种程度上取得领先。