GCHandle.Alloc() を使用し、構造体を固定します:-)
public static byte[] Foo<T>(this T input) where T : struct
{
int size = Marshal.SizeOf(typeof(T));
var result = new byte[size];
var gcHandle = GCHandle.Alloc(input, GCHandleType.Pinned);
Marshal.Copy(gcHandle.AddrOfPinnedObject(), result, 0, size);
gcHandle.Free();
return result;
}
...しかし、「Marshal.SizeOf」は bool と char に間違ったサイズを与えます。
SizeOf 関数を書き直しました (少しクレイジーに見えますが、非常に高速です)。
static readonly Dictionary<long, int> SizeOfDict = new Dictionary<long, int>();
//[MethodImpl(MethodImplOptions.AggressiveInlining)] // not supported below 4.5
public static int SizeOf<T>() where T : struct
{
// --- Highspeed Compiler-Hack ---
// if (typeof(T) == typeof(byte)) return sizeof(byte); // uncomment if .Net >= 4.5
// if (typeof(T) == typeof(sbyte)) return sizeof(sbyte);
// if (typeof(T) == typeof(ushort)) return sizeof(ushort);
// if (typeof(T) == typeof(short)) return sizeof(short);
// if (typeof(T) == typeof(uint)) return sizeof(uint);
// if (typeof(T) == typeof(int)) return sizeof(int);
// if (typeof(T) == typeof(ulong)) return sizeof(ulong);
// if (typeof(T) == typeof(long)) return sizeof(long);
// if (typeof(T) == typeof(float)) return sizeof(float);
// if (typeof(T) == typeof(double)) return sizeof(double);
// --- fix wrong sizes ---
if (typeof(T) == typeof(char)) return sizeof(char);
if (typeof(T) == typeof(bool)) return sizeof(bool);
long id = (long)typeof(T).TypeHandle.Value;
int len;
if (!SizeOfDict.TryGetValue(id, out len))
{
len = Marshal.SizeOf(typeof(T));
SizeOfDict.Add(id, len);
}
return len;
}