After a lot of research, I created this wrapper which I think fits very well to my needs. My project is a TCP server and I will be using this wrapper every time the server receives a packet. Basically, the wrapper will work marshaling raw byte[]
into higher-level representation of the data as marshalable structs.
What do you think about this wrapper? Any hint on how I can improve it? I'm very concerned about performance.
public static class MyMarshal
{
/// <summary>
/// Marshals a raw buffer to a given marshalable struct.
/// </summary>
public static unsafe T GetStructure<T>(byte[] buffer) where T : struct
{
fixed (byte* bufferPin = buffer)
{
return (T)Marshal.PtrToStructure(new IntPtr(bufferPin), typeof(T));
}
}
/// <summary>
/// Marshals a given T instance into a raw buffer.
/// </summary>
public static unsafe byte[] GetBytes<T>(T obj) where T : struct
{
byte[] rawBuffer = new byte[Marshal.SizeOf(obj)];
fixed (byte* rawBufferPin = rawBuffer)
{
Marshal.StructureToPtr<T>(obj, new IntPtr(rawBufferPin), false);
}
return rawBuffer;
}
/// <summary>
/// Crates a zero-initialized marshaled instance of T
/// </summary>
public static unsafe T CreateEmpty<T>() where T : struct
{
int typeSize = Marshal.SizeOf(typeof(T));
byte* rawBuffer = stackalloc byte[typeSize];
for (int i = 0; i < typeSize; i++)
rawBuffer[i] = 0;
T zeroInited = (T)Marshal.PtrToStructure(new IntPtr(rawBuffer), typeof(T));
return zeroInited;
}
}
Summing up, the wrapper have 3 methods:
GetStructure
(used right after I receive any valid packet to get the respective structure)GetBytes
(used when I want to send a packet to a client, converts a given struct value to a raw buffer to be send to the client)CreateEmpty
(used to create a zero-initialized instance of a given struct. This method is used when I have complex structures with non-blittable arrays, etc. The goal of this method is to have a generic zero-initializer method even to non-blittable structs - those with non-blittable arrays and/or strings).
I want to raise another questions too:
- What do you think about this mixed use of unsafe code and the
Marshal
class? Is there any problem on using that way? - In the method
MyMarshal.CreateEmpty
, what do you think about thestackalloc
usage? Some structures that will be initialized with this method will be a little big (usually something between 100 and 1024 bytes). Is there any downside or danger of allocating this length in the stack several times per seconds? I'm expecting to process something around 5k packet per second.
Also, he TCP server will work asynchronously using the async/await pattern, so I don't expect to deal with shared stated and other common problems to a multi-threaded application.
public static unsafe T CrateEmpty
vspublic static unsafe T CreateEmpty
\$\endgroup\$ – Heslacher Jul 27 '16 at 15:02