题
我最近遇到一种情况,我需要建立一个通用的方法读取的数据类型出的一个字阵列。
我已经创建了以下类别:
public class DataStream
{
public int Offset { get; set; }
public byte[] Data { get; set; }
public T Read<T>() 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;
}
}
}
现在,de分配问题放在一边,这个代码没有编纂这个信息:
Cannot take the address of, get the size of, or declare a pointer to a managed type ('T')
其中,似乎很奇怪因为你应该能够做到的上述行动的基础上 where T : struct
制约因素的方法。
如果这代码是可怕的错误,是否有任何简单的方式采取了一系列的字节,并将它们转换成'T
'类型?
谢谢!
解决方案
而不是试图通过指针操作要做到这一点,你应该切换您的代码中使用的 Mashal.PtrToStructure 。此方法是专门为这种情况设计的。
其他提示
由于答复中已经给出的,让我解释为什么你的原始代码没有为你工作:
其中,似乎很奇怪因为你应该能够做到的上述行动的基础上在T:结构上的约束方法。
不是真的。你可以拥有原始指向 非托管的类型.这个定义如下的C#语言规范(18.2):
不像引用(数值的基准类型),指针不是跟踪通过的垃圾收集器—垃圾回收已经没有知识的指标和数据来,他们一点。由于这个原因一指针是不允许的要点参考或结构,包含参考文献,所指的类型的指针必须是一个 非管理型.一个 非管理型 是任何类型,不是一个参考型并不包含参考型领域,在任何级别的嵌套。换句话说, 非管理型 是下列之一:
sbyte
,byte
,short
,ushort
,int
,uint
,long
,ulong
,char
,float
,double
,decimal
, 或bool
.- 任何 枚举型.
- 任何 指针型.
- 任何用户定义的 结构类型 包含的领域 非托管的类型 只。
所以有一些限制,和一个通用的方法, T:struct
可能会或可能不符合他们的任何具体的实例,因此构建喜欢 T*
是非法的。这将是很好有一个特别的通用类型参数的约束复盖非托管的类型,但是因为它的立场,没有一个在CLR。
假设:
- 顺序或明确的结构(否则非常糟糕的主意)
- 正确的数据尺寸(你应该预先检查和扔)
unsafe TStruct BytesToStructure<TStruct>(byte[] data) where TStruct : struct
{
fixed (byte* dataPtr = data)
return (TStruct)Marshal.PtrToStructure(new IntPtr(dataPtr), typeof(TStruct));
}
unsafe byte[] StructureToBytes<TStruct>(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
您将有一个C ++ / CLI项目添加到您的Visual Studio解决方案虽然。