C#使用反射获取不安全结构体中固定字段的类型

12

我正在尝试使用一些固定字段获取不安全结构的字段类型。 固定字段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


1
你尝试过将 TestProjectNS.MyStruct+e__FixedBuffer0 视为一种类型并检查其成员吗?如果固定缓冲区被实现为嵌套结构体,那也不会让我感到惊讶。 - CodesInChaos
3个回答

7

可以通过应用于固定大小缓冲区语句的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

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

生成的结构体名称包含一些特殊字符,字段和嵌套类型都被标记为安全关键。


+1 不错的解决方案。你是自己写的还是从 Reflector 上找到的?看看我从 Reflector 上得到的代码。 - Mikael Östberg
代码来自我在LinqPad中转储的“FieldInfo”。因此,您从反射器中获取的代码肯定更准确。 - CodesInChaos
好的答案,由于该字段是嵌套的,因此必须深入到嵌套字段中。 - Joe

-1

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

你的if条件有点过于急切了。它认为每个嵌套类型都是一个固定数组。 - CodesInChaos
@Code - 是的,这可能不是最好的方法。你的答案很好 :) - SwDevMan81

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接