From the MSDN Library article for LayoutKind enumeration:
The precise position of each member of an object in unmanaged memory is explicitly controlled, subject to the setting of the StructLayoutAttribute.Pack field. Each member must use the FieldOffsetAttribute to indicate the position of that field within the type.
Relevant phrase highlighted, this is not happening in this program, the pointer is still very much dereferencing managed memory.
And yes, what you are seeing is identical to what happens when a struct contains a member of type DateTime, a type that has [StructLayout(LayoutKind.Auto)] applied. The field marshaller code in the CLR that determines layout makes an effort to honor LayoutKind.Sequential for managed structs as well. But it will quickly give up without a squeal if it encounters any member that conflicts with this goal. A struct that itself is not sequential is sufficient for that. You can see this being done in the SSCLI20 source, src/clr/vm/fieldmarshaler.cpp, search for fDisqualifyFromManagedSequential
Which will make it switch to automatic layout, the same layout rule that's applied to classes. It rearranges fields to minimize the padding between members. With the net effect that the amount of memory required is smaller. There are 7 bytes of padding after the "Bool" member, unused space to get the "Long" member aligned to an address that's a multiple of 8. Very wasteful of course, it fixes that by making the long the first member in the layout.
So instead of the explicit layout with /* offset - size */ annotated:
public int A; /* 0 - 4 */
public int B; /* 4 - 4 */
public bool Bool; /* 8 - 1 */
// padding /* 9 - 7 */
public long Long; /* 16 - 8 */
public Explicit C; /* 24 - 8 */
/* Total: 32 */
It comes up with:
public long Long; /* 0 - 8 */
public int A; /* 8 - 4 */
public int B; /* 12 - 4 */
public bool Bool; /* 16 - 1 */
// padding /* 17 - 3 */
public Explicit C; /* 20 - 8 */
/* Total: 28 */
With an easy 4 bytes of memory saved. The 64-bit layout requires additional padding to ensure that the long is still aligned when it is stored in an array. This is all highly undocumented and subject to change, be sure to never take a dependency on managed memory layout. Only Marshal.StructureToPtr() can give you a guarantee.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…