Diseño del tipo de valor .NET en la memoria

Tengo los siguientes tipos de valor .NET:

[StructLayout(LayoutKind.Sequential)]
public struct Date
{
    public UInt16 V;
}

[StructLayout(LayoutKind.Sequential)]
public struct StringPair
{
    public String A;
    public String B;
    public String C;
    public Date D;
    public double V;
}

Tengo un código que pasa un puntero a un tipo de valor a un código no administrado, junto con las compensaciones descubiertas al llamar a System.Runtime.InteropServices.Marshal.OffsetOf. El código no administrado está llenando la fecha y los valores dobles.

Las compensaciones que se informan para la estructura StringPair son exactamente lo que yo esperaría: 0, 8, 16, 24, 32

Tengo el siguiente código en una función de prueba:

FieldInfo[] fields = typeof(StringPair).GetFields(BindingFlags.Instance|BindingFlags.Public);

for ( int i = 0; i < fields.Length; i++ )
{
    int offset = System.Runtime.InteropServices.Marshal.OffsetOf(typeof(StringPair), fields[i].Name).ToInt32();

    Console.WriteLine(String.Format(" >> field {0} @ offset {1}", fields[i].Name, offset));
}

Lo que imprime exactamente estas compensaciones.

 >> field A @ offset 0
 >> field B @ offset 8
 >> field C @ offset 16
 >> field D @ offset 24
 >> field V @ offset 32

Luego tengo un código de prueba: foreach (par de StringPair en pares) {Fecha d = pair.D; doble v = par.V; ...

Que tiene el siguiente ensamblador asociado con él en el depurador:

               Date d = pair.D;
0000035d  lea         rax,[rbp+20h] 
00000361  add         rax,20h 
00000367  mov         ax,word ptr [rax] 
0000036a  mov         word ptr [rbp+000000A8h],ax 
00000371  movzx       eax,word ptr [rbp+000000A8h] 
00000378  mov         word ptr [rbp+48h],ax 

                double v = pair.V;
0000037c  movsd       xmm0,mmword ptr [rbp+38h] 
00000381  movsd       mmword ptr [rbp+50h],xmm0 

Está cargando el campo D en el desplazamiento 32 (0x20) y el campo V en el desplazamiento 24 (0x38-0x20). El JIT ha cambiado el orden alrededor. El depurador de Visual Studio también muestra este orden invertido.

¿¡Por qué!? He estado sacándome el pelo tratando de ver dónde está yendo mal mi lógica. Si cambio el orden de D y V en la estructura, entonces todo funciona, pero este código debe poder tratar con una arquitectura de complementos donde otros desarrolladores han definido la estructura, y no se puede esperar que recuerden las reglas de diseño arcano.

Respuestas a la pregunta(3)

Su respuesta a la pregunta