如何使用反射设置固定的缓冲区字段元素

本文关键字:缓冲区 字段 元素 何使用 反射 设置 | 更新日期: 2023-09-27 17:53:39

下面是一个典型的unsafe结构体声明,它包含一个固定的缓冲区字段:

[StructLayout(LayoutKind.Explicit, Pack = 1)]
public unsafe struct MyStruct
{
    ...
    [FieldOffset(6)]
    public fixed ushort MyFixedBuffer[28];
    ...
}

如何使用反射设置MyFixeBuffer的元素?

如何使用反射设置固定的缓冲区字段元素

您不需要反射。你需要的是你想要设置的结构体的地址。然后可以使用

byte* pStruct = xxxx
byte* pMyFixedBuffer = pStruct+6;  // FieldOffset 6 tells me this
*(pMyFixedBuffer+i) = yourBytevalue;  // set i-th element in MyFixedBuffer

我猜你有问题,以获得结构体的地址,因为它很可能是通过值传递给一些方法,你想在不同的值补丁。只要结构体没有被赋值给可以从外部以某种方式访问的类成员变量,就不能在运行时修补任何东西。

因为你的类是公共的,字段也是公共的,所以根本没有理由使用反射或不安全的代码。但我猜这门课并不是你们真正纠结的。

您可以使用反射来查找类布局,但在某些时候,您需要硬编码您实际想要修补的字段。为此,您可以使用从反射获得的布局信息,然后在运行时确定地址。您需要获取字段的FieldOffset属性值,然后使用它作为指针偏移量来获取它。

请注意,数组MyFixedBuffer在结构体中不是一个真正的数组,因为它嵌入在结构体中。通常的对象指针GetType不会工作,因为数组不是管理的,而是一个固定大小的缓冲区,根本没有MT(方法表指针)。在这一点上,您需要处理原始偏移量并在您需要的字节中进行修补。

下面是一个使用反射的例子,如果你想知道如何处理任何值类型,如果你想构建一些使用值类型或序列化器的动态东西。

[StructLayout(LayoutKind.Explicit, Pack = 1)]
public unsafe struct MyStruct
{
    [FieldOffset(6)]
    public fixed ushort MyFixedBuffer[28];
    [FieldOffset(62)]
    public byte Next;
}
class Program
{
    unsafe static void Main(string[] args)
    {
        var field = typeof(MyStruct).GetField("MyFixedBuffer");
        int offset = field.CustomAttributes.Where(x => x.AttributeType.Equals(typeof(FieldOffsetAttribute)))
                                                .SelectMany(x => x.ConstructorArguments)
                                                .Select(x => x.Value)
                                                .Cast<int>()
                                                .First();
        KeyValuePair<Type,int> fixedBufferDescription = field.CustomAttributes.Where(x => x.AttributeType.Equals(typeof(FixedBufferAttribute)))
                                                   .Select(x => x.ConstructorArguments)
                                                   .Select(x => new KeyValuePair<Type, int>((Type)x[0].Value, (int)x[1].Value))
                                                   .First();
        int fixedBuferLen = Marshal.SizeOf(fixedBufferDescription.Key) * fixedBufferDescription.Value;

        MyStruct tmp = new MyStruct();
        byte* raw = (byte*) &tmp;
        short* pmyArray = (short *) (raw + offset);
        for (int i = 0; i < fixedBuferLen/Marshal.SizeOf(fixedBufferDescription.Key); i++)
        {
            *(pmyArray + i) = (short) i;
        }
    }
}

应该可以了。