CodeGo.net>如何设置使用反射固定缓冲区字段元素?

这是一个典型的不安全结构声明,其中包含一个固定的缓冲区字段:

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

    }
}

这应该够了吧.

上一篇:在Silverlight中BigEndianBitConverter?


下一篇:Java 中的 CAS 简述及原理解析