Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make these struct functions generic?

I have these two functions which read a stream into a buffer and loads it into the given struct.

    TestStruct1 ReadRecFromStream2(Stream stream)
    {
        byte[] buffer = new byte[Marshal.SizeOf(typeof(TestStruct1))];
        stream.Read(buffer, 0, 128);
        GCHandle handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
        try
        {
            return (TestStruct1)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(TestStruct1));
        }
        finally
        {
            handle.Free();
        }
    }

    TestStruct2 ReadRecFromStream(Stream stream)
    {
        byte[] buffer = new byte[Marshal.SizeOf(typeof(TestStruct2))];
        stream.Read(buffer, 0, 128);
        GCHandle handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
        try
        {
            return (TestStruct2)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(TestStruct2));
        }
        finally
        {
            handle.Free();
        }
    }

I'd like to combine these into a generic function to take either of the structs, I'm just unsure what the proper way to do this is.

Is this the correct way?

    private T ReadRecFromStream<T>(Stream stream)
    {
        byte[] buffer = new byte[Marshal.SizeOf(typeof(T))];
        stream.Read(buffer, 0, HeaderSize);
        GCHandle handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
        try
        {
            return (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T));
        }
        finally
        {
            handle.Free();
        }
    }
like image 614
pfinferno Avatar asked Oct 30 '22 07:10

pfinferno


1 Answers

Maybe you can use these methods to convert from and to byte[]:

public static unsafe byte[] ToBytes<T>(this T value)
    where T : struct
{
    var result = new byte[Marshal.SizeOf(typeof(T))];
    fixed (byte* b = &result[0])
    {
        var p = new IntPtr(b);
        Marshal.StructureToPtr(value, p, false);
    }

    return result;
}

public static unsafe T FromBytes<T>(this byte[] bytes, int startIndex = 0)
    where T : struct
{
    fixed (byte* b = &bytes[startIndex])
    {
        var p = new IntPtr(b);
        return (T)Marshal.PtrToStructure(p, typeof(T));
    }
}

Using this your methods could be changed to:

T ReadRecFromStream<T>(Stream stream)
    where T : struct
{
    byte[] buffer = new byte[Marshal.SizeOf(typeof(T))];
    stream.Read(buffer, 0, buffer.Length);
    return buffer.FromBytes<T>()
}

Read would work similar.

like image 63
Sebastian Schumann Avatar answered Nov 09 '22 01:11

Sebastian Schumann