C # Получить тип фиксированного поля в небезопасной структуре с отражением - PullRequest
11 голосов
/ 23 марта 2011

Я пытаюсь получить типы полей небезопасной структуры, используя некоторые фиксированные поля.Фиксированные поля FieldType не возвращают фактический тип.

[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";
   }

}

Вывод:

Поле1: System.UInt32

Поле 2: TestProjectNS.MyStruct+<Field2>e__FixedBuffer0

Поле 3: System.UInt64


Я ищу Field2, чтобы сказать мне, что sbyte вместо TestProjectNS.MyStruct+<Field2>e__FixedBuffer0

Ответы [ 3 ]

6 голосов
/ 23 марта 2011

Базовый тип буфера фиксированного размера может быть получен через FixedBufferAttribute, который применяется к оператору буфера фиксированного размера.

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";
}

Или короткая версия для одного поля:

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

Как CodeInChaos, мне также нужно было отразить это, но у меня есть 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;
    }
}

Удивительный вопрос!

4 голосов
/ 23 марта 2011

TestProjectNS.MyStruct+<Field2>e__FixedBuffer0 является вложенным типом.Он содержит одно поле нужного вам базового типа.

Итак, учитывая FieldInfo вашего массива фиксированного размера, вы можете сделать:

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

То, что генерирует компилятор C #, выглядит примерно так:следующее:

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

За исключением того, что имя сгенерированной структуры содержит несколько специальных символов, а поле и вложенный тип помечены как критические для безопасности.

0 голосов
/ 23 марта 2011

CodeInChaos это правильно.Еще один способ сделать это:

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";
   }
}
...