2011-03-23 15 views
9

Estoy tratando de obtener los tipos de campo de una estructura insegura utilizando algunos campos fijos. Los campos fijos FieldType no devuelven el tipo real.C# Obtiene el tipo de campo fijo en la estructura insegura con reflexión

[StructLayout(LayoutKind.Sequential, Pack = 1)] 
public unsafe struct MyStruct 
{ 
    public UInt32 Field1; 
    public fixed sbyte Field2[10]; 
    public UInt64 Field3; 
} 

void Test() 
{ 
    var theStruct = new MyStruct(); 
    string output = ""; 
    foreach (FieldInfo fi in theStruct.GetType().GetFields(BindingFlags.Public | BindingFlags.Instance)) 
    { 
     output += fi.Name + ": " + fi.FieldType.ToString() + "\r\n"; 
    } 

} 

Salida:

Campo1: System.UInt32

Campo2: TestProjectNS.MyStruct+<Field2>e__FixedBuffer0

Campo3: System.UInt64


estoy buscando Field2 decirme que es sbyte en lugar de TestProjectNS.MyStruct+<Field2>e__FixedBuffer0

+1

¿Ha intentado tratar 'TestProjectNS.MyStruct + e__FixedBuffer0' como un tipo y ha marcado sus miembros? No me sorprendería si los búferes fijos se implementaran como estructuras anidadas. – CodesInChaos

Respuesta

5

El Tamaño fijo tipo subyacente de búfer puede ser recuperada a través de la FixedBufferAttribute, que se aplica en el estado de búfer de tamaño fijo.

foreach (FieldInfo fi in typeof(MyStruct).GetFields(BindingFlags.Public | BindingFlags.Instance)) 
{ 
    var attr = fi.GetCustomAttributes(typeof(FixedBufferAttribute), false); 
    if(attr.Length > 0) 
     output += fi.Name + ": " + ((FixedBufferAttribute)attr[0]).ElementType + "\r\n"; 
    else 
     output += fi.Name + ": " + fi.FieldType + "\r\n"; 
} 

O el único campo de versión corta:

var type = typeof (MyStruct) 
      .GetField("Field2") 
      .GetCustomAttributes(typeof (FixedBufferAttribute), false) 
      .Cast<FixedBufferAttribute>() 
      .Single() 
      .ElementType; 

Como, también es necesario para reflejar CodeInChaos ella, pero tengo la FixedBufferAttribute:

[StructLayout(LayoutKind.Sequential, Pack=1)] 
public struct MyStruct 
{ 
    public uint Field1; 
    [FixedBuffer(typeof(sbyte), 10)] 
    public <Field2>e__FixedBuffer0 Field2; 
    public ulong Field3; 
    // Nested Types 
    [StructLayout(LayoutKind.Sequential, Size=10), CompilerGenerated, UnsafeValueType] 
    public struct <Field2>e__FixedBuffer0 
    { 
     public sbyte FixedElementField; 
    } 
} 

pregunta impresionante!

+0

+1 Excelente respuesta. Esto era exactamente lo que estaba buscando. – Joe

3

TestProjectNS.MyStruct+<Field2>e__FixedBuffer0 es un tipo anidado. Contiene un solo campo del tipo subyacente que desea.

Por lo tanto, dada la FieldInfo de la matriz de tamaño fijo que puede hacer:

Type bufferFieldType=fixedBufferFieldInfo.FieldType.GetFields(BindingFlags.Public | BindingFlags.Instance).Single().FieldType; 

Lo que genera el compilador de C# tiene una apariencia similar a la siguiente:

[StructLayout(LayoutKind.Sequential, Pack = 1)] 
public unsafe struct MyStruct 
{ 
    [StructLayout(LayoutKind.Sequential, Pack = 1, Size=10)] 
    public struct Field2e__FixedBuffer0 
    { 
     public sbyte FixedElementField; 
    } 
    public UInt32 Field1; 
    public Field2e__FixedBuffer0 Field2; 
    public UInt64 Field3; 
} 

salvo que el nombre de la estructura generada contiene algunos caracteres especiales y tanto el campo como el tipo anidado están marcados como de seguridad crítica.

+0

+1 Buen trabajo de investigación. – SwDevMan81

+0

+1 Buena solución. ¿Lo escribiste o lo obtuviste de Reflector? Echa un vistazo al código que obtuve de Reflector. –

+0

El código es del 'FieldInfo' que descargué en LinqPad. Entonces, su código del reflector es ciertamente más preciso. – CodesInChaos

-1

CodeInChaos lo tiene todo. Otra manera de hacerlo:

foreach (FieldInfo fi in theStruct.GetType().GetFields(BindingFlags.Public | BindingFlags.Instance)) 
{ 
    if (fi.FieldType.IsNested) 
    { 
     output += fi.Name + ": " + 
      fi.FieldType.GetFields()[0].FieldType.ToString() + "\r\n"; 
    } 
    else 
    { 
     output += fi.Name + ": " + fi.FieldType.ToString() + "\r\n"; 
    } 
} 
+0

Su condición if es un poco más de impaciente. Cree que cada tipo anidado es una matriz fija. – CodesInChaos

+0

@Code - Sí, probablemente no sea la mejor manera de hacerlo. Tu respuesta es buena :) – SwDevMan81

Cuestiones relacionadas