I'm trying to get the field types of an unsafe struct using some fixed fields. The fixed fields FieldType do not return the actual type.
[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";
}
}
Output:
Field1: System.UInt32
Field2: TestProjectNS.MyStruct+<Field2>e__FixedBuffer0
Field3: System.UInt64
I'm looking for Field2
to tell me it's sbyte
instead of TestProjectNS.MyStruct+<Field2>e__FixedBuffer0
The Fixed Size Buffer's underlying type can be retrieved through the FixedBufferAttribute
, which is applied on the fixed size buffer statement.
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";
}
Or the single field short version:
var type = typeof (MyStruct)
.GetField("Field2")
.GetCustomAttributes(typeof (FixedBufferAttribute), false)
.Cast<FixedBufferAttribute>()
.Single()
.ElementType;
As CodeInChaos, I also needed to reflect it, but I do have the 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;
}
}
Awesome question!
TestProjectNS.MyStruct+<Field2>e__FixedBuffer0
is a nested type. It contains a single field of the underlying type you want.
So given the FieldInfo
of your fixed size array you can do:
Type bufferFieldType=fixedBufferFieldInfo.FieldType.GetFields(BindingFlags.Public | BindingFlags.Instance).Single().FieldType;
What the C# compiler generates looks similar to the following:
[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;
}
Except that the name of the generated struct contains a few special characters and the both the field and the nested type are marked as security critical.
CodeInChaos has it right. Another way you can do it:
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";
}
}