How can I set a fixed element of a buffer field using reflection?

Here's a typical structure declaration unsafe

that contains a fixed buffer field:

[StructLayout(LayoutKind.Explicit, Pack = 1)]
public unsafe struct MyStruct
{
    ...

    [FieldOffset(6)]
    public fixed ushort MyFixedBuffer[28];

    ...
}

      

How do I set an element MyFixeBuffer

using reflection?

+3


source to share


1 answer


You don't need to think. You need the address of the structure you want to set up. Then you can use

byte* pStruct = xxxx
byte* pMyFixedBuffer = pStruct+6;  // FieldOffset 6 tells me this

*(pMyFixedBuffer+i) = yourBytevalue;  // set i-th element in MyFixedBuffer

      

I am guessing that you are having trouble getting the address of a struct in general, because it is most likely passed by value to some methods where you want to fix different values. Until the structure is assigned to a member variable of the class, which instance you can somehow get from the outside, you cannot fix anything at runtime.

Since your class is public and the field is public, there is also no reason to use reflection or unsafe code at all. But I think this class is not the one you are struggling with.

You can use reflection to learn about the layout of the class, but at some point you need to hard-code which field you really want to schedule. To do this, you can use the layout information obtained from reflection and then determine the address at runtime. You need to get the FieldOffset attribute value for the field and then use that as the pointer offset to get it.



Note that the MyFixedBuffer array is not a real array in the structure as it is embedded in the structure. A regular GetType pointer object will not work as the array is not manipulated, but a fixed size buffer that has no MT (method table pointer) at all. At this point, you need to deal with the raw offsets and the patch in the bytes you are after.

Below is an example that uses reflection if you want to know how to deal with any value type, if you want to build something dynamic that uses value types or a serializer for example.

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

    }
}

      

This should do the trick.

+2


source







All Articles