Common BitConverter Method?

Recently, I came across a situation where I need to create a general method for reading a data type from a byte array.

I created the following class:

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; } } } 

Now, if the problems with the allocated allocation aside, this code does not compile with this message:

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

Which seems odd because you should be able to perform the above operations based on where T : struct constraint on the method.

If this code is terribly incorrect, is there an easy way to take a series of bytes and type them into type ' T ?

Thanks!

+4
source share
5 answers

Instead of trying to do this with pointer manipulation, you should switch your code to use Mashal.PtrToStructure . This method is specifically designed for this scenario.

+8
source

Since the answer has already been given, let me explain why your source code did not work for you:

Which seems odd because you should be able to perform the above operations based on the T: struct constraint on the method.

Not really. You may have raw pointers to unmanaged types. In the C # language specification (18.2), this is defined as follows:

Unlike references (values ​​of reference types), pointers are not tracked by the garbage collector - the garbage collector does not know the pointers and the data that they point to. For this reason, the pointer is not allowed to specify a link or structure containing links, and the type of pointer referent must be unmanageable. An unmanaged type is any type that is not a reference type and does not contain fields of a reference type at any nesting level. In other words, an unmanaged type is one of the following:

  • sbyte , byte , short , ushort , int , uint , long , ulong , char , float , double , decimal , or bool .
  • Any type of listing.
  • Any type of pointer.
  • Any custom struct type that contains only fields of unmanaged types.

Thus, there are quite a few restrictions, and for the general method T:struct may or may not correspond to them for any particular instance, therefore a construction of type T* is illegal. It would be nice to have a special type constraint on the type type to cover unmanaged types, but as it is, there is not one in the CLR.

+7
source

At some point, I wrote this article explaining how to do this, but many times faster than Marshal.PtrToStructure. The code example uses dynamic code generation to copy the generated type T to / from the bitstream.

+2
source

Assuming that:

  • Consistent or explicit structure (otherwise a very bad idea)
  • Correct data sizes (you must first check and discard)

 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; } 
+1
source

I wrote this a while ago to do the same: http://www.codeproject.com/Articles/33713/Generic-BinaryReader-and-BinaryWriter-Extensions

You need to add the C ++ / CLI project to the Visual Studio solution.

0
source

All Articles