通用BitConverter式方法?

Rya*_*ker 5 c# unsafe marshalling

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

我创建了以下类:


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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

Cannot take the address of, get the size of, or declare a pointer to a managed type ('T')

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

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

谢谢!

Ree*_*sey 9

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


Pav*_*aev 7

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

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

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

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

  • sbyte,byte,short,ushort,int,uint,long,ulong,char,float,double,decimal,或bool.
  • 任何枚举类型.
  • 任何指针类型.
  • 任何用户定义的struct-type,仅包含非托管类型的字段.

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