16

The struct System.DateTime and its cousin System.DateTimeOffset have their structure layout kinds set to "Auto". This can be seen with:

typeof(DateTime).IsAutoLayout    /* true */

or:

typeof(DateTime).StructLayoutAttribute.Value    /* Auto */

or it can be seen from the IL which declares:

.class public auto ansi serializable sealed beforefieldinit System.DateTime
              ¯¯¯¯

Normally a struct (that is a .NET value type which is not an enum) written with C# will have layout "Sequential" (unless a StructLayoutAttribute has been applied to specify another layout).

I searched through some common BCL assemblies, and DateTime and DateTimeOffset were the only publicly visible structs I found with this layout.

Does anyone know why DateTime has this unusual struct layout?

Jeppe Stig Nielsen
  • 60,409
  • 11
  • 110
  • 181
  • 1
    Interesting fact. The documentation on `Auto` says *The runtime automatically chooses an appropriate layout for the members of an object in unmanaged memory. Objects defined with this enumeration member cannot be exposed outside of managed code. Attempting to do so generates an exception.* Maybe this is used to enforce usage only in managed code. Reason for that might be that the layout changed several times in .NET history (just an assumption). More: http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.layoutkind.aspx – ZoolWay Feb 19 '14 at 13:22
  • `auto` seems ok, maybe the question should be why so few other types use it. – H H Feb 19 '14 at 13:22
  • @ZoolWay I also thought along those lines. Note that we can still use the `DateTime*` pointer type in C#, with `unsafe` context, for example this program works fine: `unsafe { int[] memory = { 123, 456, 789, 333, 666, 999, }; fixed (int* pointer = &memory[0]) { var pointer2 = (DateTime*)pointer; Console.WriteLine(pointer2->DayOfWeek); pointer2 += 2; Console.WriteLine(pointer2->DayOfWeek); } }`. – Jeppe Stig Nielsen Feb 19 '14 at 13:40

1 Answers1

14

This is going to require speculation, this decision was made a long time ago, well before .NET 1.0 shipped. The attribute on System.DateTime is at best a micro-optimization, not uncommon in .NET code. It is somewhat appropriate, the struct has only one field so there's never any issue with layout. The ones for the internal CustomAttribute structs were probably done by the same programmer. Doesn't matter either, unmanaged code never sees them.

The one for System.DateTimeOffset was done much later and almost certainly a copy-paste bug.

That programmer got away with it, no reason for the CLR to re-arrange the layout from the sequential version. Re-arranging with auto-layout occurs when the struct contains padding between fields that is large enough to fit another small field. Not the case for DateTimeOffet.

Some odds you'll get a Microsoft guru to pay attention to this when you file a feedback report for DateTimeOffset. It is wrong afaik. Post it to connect.microsoft.com

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • Ineteresting. Will consider filing that bug report. But the struct `TimeSpan` is as old as `DateTime`, it also only has one instance field, so why was this "micro-optimaization" not applied to `TimeSpan`? Do you have any idea? – Jeppe Stig Nielsen Feb 19 '14 at 14:38
  • 5
    TimeSpan is [ComVisible(true)], unlike DateTime. – Hans Passant Feb 19 '14 at 15:09
  • [Submitted to Connect](https://connect.microsoft.com/VisualStudio/feedback/details/820333/the-struct-type-system-datetimeoffset-has-layout-auto-even-if-it-has-two-instance-fields). – Jeppe Stig Nielsen Feb 20 '14 at 21:34
  • 2
    Are you sure the Auto layout on `DateTime` is really innocent just because `DateTime` has only a single field? I hope you will read [an answer I just submitted](http://stackoverflow.com/a/21960547/1336654) in another thread, where the Auto layout on a one-field struct (similar to `DateTime`) seems to propagate to the layout of a "composite" struct with Sequential layout. Maybe you can comment there if you know if that is expected or not. – Jeppe Stig Nielsen Feb 22 '14 at 21:14
  • 1
    Sure, it no longer makes an attempt to keep it sequential. You can see this in the SSCLI20 source, src/clr/vm/fieldmarshaler.cpp, search for "fDisqualifyFromManagedSequential". – Hans Passant Feb 22 '14 at 23:31
  • However with an enum (for example `public enum Test : long { }`) as member, the same thing does not happen, even if an enum looks like a one-field value type with layout Auto? – Jeppe Stig Nielsen Feb 23 '14 at 10:31
  • An enum is not a struct and has no layout. The declaration for value types you see in mscorlib is only relevant when the value type is boxed. – Hans Passant Feb 23 '14 at 10:44