Nothing can beat the performance of exyi's provided solution. I have no problems with unsafe
code, but something in the corresponding BitConverter
class methods (http://referencesource.microsoft.com/#mscorlib/system/bitconverter.cs) really concerns me - they do alignment checks and use different implementation for unaligned cases. Below is a much safer pure C# solution - it's probably a little bit slower (but that should be measured, you never know), but should be much faster than the original. As a bonus, I've added explicit name methods (similar to those in BitConverter
) additional to using bytes.To<int>()
(which is ok, but kind of weird) you can use more convenient bytes.ToInt32()
(which should be faster than generic method).
public static class BitConverter<T> where T : struct
{
public static readonly Func<byte[], int, T> To = GetFunc();
static Func<byte[], int, T> GetFunc()
{
var type = typeof(T);
if (type == typeof(bool)) return Cast(BitConverter.ToBoolean);
if (type == typeof(sbyte)) return Cast(Extensions.ToSByte);
if (type == typeof(byte)) return Cast(Extensions.ToByte);
if (type == typeof(short)) return Cast(BitConverter.ToInt16);
if (type == typeof(ushort)) return Cast(BitConverter.ToUInt16);
if (type == typeof(int)) return Cast(BitConverter.ToInt32);
if (type == typeof(uint)) return Cast(BitConverter.ToUInt32);
if (type == typeof(long)) return Cast(BitConverter.ToInt64);
if (type == typeof(ulong)) return Cast(BitConverter.ToUInt64);
if (type == typeof(float)) return Cast(BitConverter.ToSingle);
if (type == typeof(double)) return Cast(BitConverter.ToDouble);
throw new NotSupportedException();
}
static Func<byte[], int, T> Cast<U>(Func<byte[], int, U> func) { return (Func<byte[], int, T>)(object)func; }
}
public static class Extensions
{
public static bool ToBoolean(this byte[] bytes, int offset = 0) { return BitConverter.ToBoolean(bytes, offset); }
public static sbyte ToSByte(this byte[] bytes, int offset = 0) { return unchecked((sbyte)bytes[offset]); }
public static byte ToByte(this byte[] bytes, int offset = 0) { return bytes[offset]; }
public static short ToInt16(this byte[] bytes, int offset = 0) { return BitConverter.ToInt16(bytes, offset); }
public static ushort ToUInt16(this byte[] bytes, int offset = 0) { return BitConverter.ToUInt16(bytes, offset); }
public static int ToInt32(this byte[] bytes, int offset = 0) { return BitConverter.ToInt32(bytes, offset); }
public static uint ToUInt32(this byte[] bytes, int offset = 0) { return BitConverter.ToUInt32(bytes, offset); }
public static long ToInt64(this byte[] bytes, int offset = 0) { return BitConverter.ToInt64(bytes, offset); }
public static ulong ToUInt64(this byte[] bytes, int offset = 0) { return BitConverter.ToUInt64(bytes, offset); }
public static float ToSingle(this byte[] bytes, int offset = 0) { return BitConverter.ToSingle(bytes, offset); }
public static double ToDouble(this byte[] bytes, int offset = 0) { return BitConverter.ToDouble(bytes, offset); }
public static T To<T>(this byte[] bytes, int offset = 0) where T : struct { return BitConverter<T>.To(bytes, offset); }
}