patterncsharpMinor
Structure to ByteArray Extension
Viewed 0 times
bytearraystructureextension
Problem
I have a need to turn various structures into byte arrays to be sent over serial port to another machine. I created generic extensions to turn any structure into a byte array and from a byte array back into a given structure.
I've not used the
Example Call:
I've not used the
Marshal class often, and I'm uncomfortable manipulating memory on this level. - Do I need to explicitly free any memory?
- Is this an efficient implementation? I'll be calling this a lot, it's important that it's efficient in both terms of memory and speed.
public static class StructureExtensions
{
public static byte[] ToByteArray(this T structure) where T : struct
{
var bufferSize = Marshal.SizeOf(structure);
var byteArray = new byte[bufferSize];
IntPtr handle = Marshal.AllocHGlobal(bufferSize);
Marshal.StructureToPtr(structure, handle, true);
Marshal.Copy(handle, byteArray, 0, bufferSize);
return byteArray;
}
public static T ToStructure(this byte[] byteArray) where T : struct
{
var packet = new T();
var bufferSize = Marshal.SizeOf(packet);
IntPtr handle = Marshal.AllocHGlobal(bufferSize);
Marshal.Copy(byteArray, 0, handle, bufferSize);
return Marshal.PtrToStructure(handle);
}
}Example Call:
var point = new Point(10,5);
byte[] serialized = point.ToByteArray();
Point deserialized = serialized.ToStructure();Solution
I haven't used it, however all of the documentation seems to suggest that you need explicitly free the memory allocated through:
With a paired call to:
You don't seem to need the handle after you've performed the marshalling, so it could be as simple as updating the function to:
Depending on the overhead of The AllocHGlobal / FreeHGlobal and if you're going to be marshalling the same structures over and over again you might be better off going with something like:
IntPtr handle = Marshal.AllocHGlobal(bufferSize);With a paired call to:
Marshal.FreeHGlobal(handle);You don't seem to need the handle after you've performed the marshalling, so it could be as simple as updating the function to:
public static byte[] ToByteArray(this T structure) where T : struct
{
var bufferSize = Marshal.SizeOf(structure);
var byteArray = new byte[bufferSize];
IntPtr handle = Marshal.AllocHGlobal(bufferSize);
try
{
Marshal.StructureToPtr(structure, handle, true);
Marshal.Copy(handle, byteArray, 0, bufferSize);
}
finally
{
Marshal.FreeHGlobal(handle);
}
return byteArray;
}Depending on the overhead of The AllocHGlobal / FreeHGlobal and if you're going to be marshalling the same structures over and over again you might be better off going with something like:
public sealed class Marshaller : IDisposable where T : struct
{
readonly IntPtr _handle;
readonly int _bufferSize;
public Marshaller()
{
_bufferSize = Marshal.SizeOf(typeof(T));
_handle = Marshal.AllocHGlobal(_bufferSize);
}
public byte[] ToByteArray(T structure)
{
var byteArray = new byte[_bufferSize];
Marshal.StructureToPtr(structure, _handle, true);
Marshal.Copy(_handle, byteArray, 0, _bufferSize);
return byteArray;
}
public T ToStructure(byte[] byteArray)
{
var packet = new T();
Marshal.Copy(byteArray, 0, _handle, _bufferSize);
return Marshal.PtrToStructure(_handle);
}
#region IDisposable Support
private bool disposedValue = false;
~Marshaller() {
Dispose();
}
public void Dispose()
{
if (!disposedValue)
{
Marshal.FreeHGlobal(_handle);
disposedValue = true;
}
GC.SuppressFinalize(this);
}
#endregion
}Code Snippets
IntPtr handle = Marshal.AllocHGlobal(bufferSize);Marshal.FreeHGlobal(handle);public static byte[] ToByteArray<T>(this T structure) where T : struct
{
var bufferSize = Marshal.SizeOf(structure);
var byteArray = new byte[bufferSize];
IntPtr handle = Marshal.AllocHGlobal(bufferSize);
try
{
Marshal.StructureToPtr(structure, handle, true);
Marshal.Copy(handle, byteArray, 0, bufferSize);
}
finally
{
Marshal.FreeHGlobal(handle);
}
return byteArray;
}public sealed class Marshaller<T> : IDisposable where T : struct
{
readonly IntPtr _handle;
readonly int _bufferSize;
public Marshaller()
{
_bufferSize = Marshal.SizeOf(typeof(T));
_handle = Marshal.AllocHGlobal(_bufferSize);
}
public byte[] ToByteArray(T structure)
{
var byteArray = new byte[_bufferSize];
Marshal.StructureToPtr(structure, _handle, true);
Marshal.Copy(_handle, byteArray, 0, _bufferSize);
return byteArray;
}
public T ToStructure(byte[] byteArray)
{
var packet = new T();
Marshal.Copy(byteArray, 0, _handle, _bufferSize);
return Marshal.PtrToStructure<T>(_handle);
}
#region IDisposable Support
private bool disposedValue = false;
~Marshaller() {
Dispose();
}
public void Dispose()
{
if (!disposedValue)
{
Marshal.FreeHGlobal(_handle);
disposedValue = true;
}
GC.SuppressFinalize(this);
}
#endregion
}Context
StackExchange Code Review Q#136007, answer score: 9
Revisions (0)
No revisions yet.