通用BitConverter式方法?

我最近遇到过一种情况,我需要创建一个通用方法来从字节数组中读取数据类型。

我创建了以下类:

public class DataStream { public int Offset { get; set; } public byte[] Data { get; set; } public T Read() where T : struct { unsafe { int dataLen = Marshal.SizeOf( typeof( T ) ); IntPtr dataBlock = Marshal.AllocHGlobal( dataLen ); Marshal.Copy( Data, Offset, dataBlock, dataLen ); T type = *( ( T* )dataBlock.ToPointer() ); Marshal.FreeHGlobal( dataBlock ); Offset += dataLen; return type; } } } 

现在,除了解除分配问题,此代码不会使用此消息进行编译:

 不能获取地址,获取大小,或声明指向托管类型('T')的指针

其中,看起来很奇怪,因为你应该能够根据方法where T : struct约束进行上述操作。

如果这段代码非常不正确,有没有简单的方法来获取一系列字节并将它们转换为’ T ‘类型?

谢谢!

您应该切换代码以使用Mashal.PtrToStructure ,而不是尝试通过指针操作来执行此操作。 此方法专为此方案设计。

既然已经给出答案,那么让我解释为什么你的原始代码不适合你:

其中,看起来很奇怪,因为你应该能够根据方法中的T:struct约束进行上述操作。

并不是的。 您可以拥有指向非托管类型的原始指针。 这在C#语言规范(18.2)中定义如下:

与引用(引用类型的值)不同,垃圾收集器不跟踪指针 – 垃圾收集器不知道指针和它们指向的数据。 因此,不允许指针指向引用或包含引用的结构,并且指针的引用类型必须是非托管类型非托管类型是任何不是引用类型的类型,并且在任何嵌套级别都不包含引用类型字段。 换句话说, 非托管类型是以下之一:

  • sbytebyteshortushortintuintlongulongcharfloatdoubledecimalbool
  • 任何枚举类型
  • 任何指针类型
  • 任何用户定义的struct-type ,仅包含非托管类型的字段。

因此存在相当多的限制,对于通用方法, T:struct对于任何特定的实例化都可能符合或不符合它们,因此像T*这样的构造是非法的。 有一个特殊的generics类型参数约束来覆盖非托管类型会很好,但就目前而言,CLR中没有一个。

有一次,我写这篇文章解释了如何做到这一点,但比Marshal.PtrToStructure快许多倍。 代码示例使用动态代码生成将通用类型T复制到比特流或从比特流复制。

假设:

  • 顺序或显式结构(否则非常糟糕)
  • 正确的数据大小(你应该预先检查并抛出)

 unsafe TStruct BytesToStructure(byte[] data) where TStruct : struct { fixed (byte* dataPtr = data) return (TStruct)Marshal.PtrToStructure(new IntPtr(dataPtr), typeof(TStruct)); } unsafe byte[] StructureToBytes(TStruct st) where TStruct : struct { var bytes = new byte[Marshal.SizeOf(st)]; fixed (byte* ptr = bytes) Marshal.StructureToPtr(st, new IntPtr(ptr), true); return bytes; } 

我写了一段时间回来做同样的事情: http : //www.codeproject.com/Articles/33713/Generic-BinaryReader-and-BinaryWriter-Extensions

但是,您必须向Visual Studio解决方案添加C ++ / CLI项目。