C# 将字节数组编组到结构
C# Marshal byte array to struct
我为我的问题找到了很多答案,而且它们都有效。我的问题是它们在速度和内存方面是否都相同。我怎么知道什么更快并且使用更少的内存。我通常不使用 Marshal 和 GCHandle 类。所以我完全是绿色的。
public static object RawDeserializer(byte[] rawData, int position, Type anyType)
{
int rawsize = Marshal.SizeOf(anyType);
if (rawsize > rawData.Length)
return null;
IntPtr buffer = Marshal.AllocHGlobal(rawsize);
Marshal.Copy(rawData, position, buffer, rawsize);
object retobj = Marshal.PtrToStructure(buffer, anyType);
Marshal.FreeHGlobal(buffer);
return retobj;
}
public static T RawDeserializer<T>(byte[] rawData, int position = 0)
{
int rawsize = Marshal.SizeOf(typeof(T));
if (rawsize > rawData.Length)
{
throw new DataMisalignedException("byte array is not the correct size for the requested type");
}
IntPtr buffer = Marshal.AllocHGlobal(rawsize);
Marshal.Copy(rawData, position, buffer, rawsize);
T retobj = (T)Marshal.PtrToStructure(buffer, typeof(T));
Marshal.FreeHGlobal(buffer);
return retobj;
}
public static T RawDeserializer<T>(byte[] bytes) where T : struct
{
T stuff;
GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
try
{
stuff = Marshal.PtrToStructure<T>(handle.AddrOfPinnedObject());
}
finally
{
handle.Free();
}
return stuff;
}
我从所有 3 种实现中都得到了想要的结果。
第一个和第二个几乎相同:不同之处在于您没有拆箱(转换为 T:struct
)第一个示例中的结果,我假设您稍后会拆箱。
第三个选项不会将内存复制到非托管堆,它只是将其固定在托管堆中,所以我认为它会分配更少的内存并且会更快。不过,我并不假装自己是真实的黄金来源,所以就去对这些选项进行性能测试吧:) BenchmarkDotNet 是一个很好的性能测试框架,可能会对你有很大帮助。
还有第三个选项可以更简洁:
public static unsafe T RawDeserializer<T>(byte[] bytes) where T : struct
{
fixed (byte* p = bytes)
return Marshal.PtrToStructure<T>((IntPtr)p);
}
您需要更改项目设置以允许不安全的代码:
为了不完全是绿色,我强烈建议阅读一本书 CLR via C#
,第 21 章 'The Managed Heap and Garbage Collection'。
我为我的问题找到了很多答案,而且它们都有效。我的问题是它们在速度和内存方面是否都相同。我怎么知道什么更快并且使用更少的内存。我通常不使用 Marshal 和 GCHandle 类。所以我完全是绿色的。
public static object RawDeserializer(byte[] rawData, int position, Type anyType)
{
int rawsize = Marshal.SizeOf(anyType);
if (rawsize > rawData.Length)
return null;
IntPtr buffer = Marshal.AllocHGlobal(rawsize);
Marshal.Copy(rawData, position, buffer, rawsize);
object retobj = Marshal.PtrToStructure(buffer, anyType);
Marshal.FreeHGlobal(buffer);
return retobj;
}
public static T RawDeserializer<T>(byte[] rawData, int position = 0)
{
int rawsize = Marshal.SizeOf(typeof(T));
if (rawsize > rawData.Length)
{
throw new DataMisalignedException("byte array is not the correct size for the requested type");
}
IntPtr buffer = Marshal.AllocHGlobal(rawsize);
Marshal.Copy(rawData, position, buffer, rawsize);
T retobj = (T)Marshal.PtrToStructure(buffer, typeof(T));
Marshal.FreeHGlobal(buffer);
return retobj;
}
public static T RawDeserializer<T>(byte[] bytes) where T : struct
{
T stuff;
GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
try
{
stuff = Marshal.PtrToStructure<T>(handle.AddrOfPinnedObject());
}
finally
{
handle.Free();
}
return stuff;
}
我从所有 3 种实现中都得到了想要的结果。
第一个和第二个几乎相同:不同之处在于您没有拆箱(转换为 T:struct
)第一个示例中的结果,我假设您稍后会拆箱。
第三个选项不会将内存复制到非托管堆,它只是将其固定在托管堆中,所以我认为它会分配更少的内存并且会更快。不过,我并不假装自己是真实的黄金来源,所以就去对这些选项进行性能测试吧:) BenchmarkDotNet 是一个很好的性能测试框架,可能会对你有很大帮助。
还有第三个选项可以更简洁:
public static unsafe T RawDeserializer<T>(byte[] bytes) where T : struct
{
fixed (byte* p = bytes)
return Marshal.PtrToStructure<T>((IntPtr)p);
}
您需要更改项目设置以允许不安全的代码:
为了不完全是绿色,我强烈建议阅读一本书 CLR via C#
,第 21 章 'The Managed Heap and Garbage Collection'。