通用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)中定义如下:
与引用(引用类型的值)不同,垃圾收集器不跟踪指针 – 垃圾收集器不知道指针和它们指向的数据。 因此,不允许指针指向引用或包含引用的结构,并且指针的引用类型必须是非托管类型 。 非托管类型是任何不是引用类型的类型,并且在任何嵌套级别都不包含引用类型字段。 换句话说, 非托管类型是以下之一:
sbyte
,byte
,short
,ushort
,int
,uint
,long
,ulong
,char
,float
,double
,decimal
或bool
。- 任何枚举类型 。
- 任何指针类型 。
- 任何用户定义的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项目。