For very simple structs which aren't Serializable and contain only base types, this works. I use it for parsing files which have a known format. Error checking removed for clarity.
using System;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
namespace FontUtil
{
public static class Reader
{
public static T Read<T>(BinaryReader reader, bool fileIsLittleEndian = false)
{
Type type = typeof(T);
int size = Marshal.SizeOf(type);
byte[] buffer = new byte[size];
reader.Read(buffer, 0, size);
if (BitConverter.IsLittleEndian != fileIsLittleEndian)
{
FieldInfo[] fields = type.GetFields();
foreach (FieldInfo field in fields)
{
int offset = (int)Marshal.OffsetOf(type, field.Name);
int fieldSize = Marshal.SizeOf(field.FieldType);
for (int b = offset, t = fieldSize + b - 1; b < t; ++b, --t)
{
byte temp = buffer[t];
buffer[t] = buffer[b];
buffer[b] = temp;
}
}
}
GCHandle h = GCHandle.Alloc(buffer, GCHandleType.Pinned);
T obj = (T)Marshal.PtrToStructure(h.AddrOfPinnedObject(), type);
h.Free();
return obj;
}
}
}
Structs need to be declared like this (and can't contain arrays, I think, haven't tried that out - the endian swap would probably get confused).
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct NameRecord
{
public UInt16 uPlatformID;
public UInt16 uEncodingID;
public UInt16 uLanguageID;
public UInt16 uNameID;
public UInt16 uStringLength;
public UInt16 uStringOffset; //from start of storage area
}
BinaryFormatteris rarely the correct choice for serializing data.BinaryFormattercan be the right choice. A savegame in a game is one of the few cases that fitsBinaryFormatterIMO.BinaryFormatteris that you must trust the file absolutely. Whoever created the file is most likely able to execute code in the context of your program.