如何使用反射设置固定的缓冲区字段元素
本文关键字:缓冲区 字段 元素 何使用 反射 设置 | 更新日期: 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;
}
}
}
应该可以了。