Generic BitConverter-like method?

蓝咒 提交于 2019-11-29 11:02:05

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

Since answer has already been given, let me just explain why your original code didn't work for you:

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

Not really. You can have raw pointers to unmanaged types. This is defined as follows in the C# language spec (18.2):

Unlike references (values of reference types), pointers are not tracked by the garbage collector — the garbage collector has no knowledge of pointers and the data to which they point. For this reason a pointer is not permitted to point to a reference or to a struct that contains references, and the referent type of a pointer must be an unmanaged-type. An unmanaged-type is any type that isn’t a reference-type and doesn’t contain reference-type fields at any level of nesting. 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 enum-type.
  • Any pointer-type.
  • Any user-defined struct-type that contains fields of unmanaged-types only.

So there are quite a few restrictions, and for a generic method, T:struct may or may not conform to them for any particular instantiation, so construct like T* is illegal. It would be nice to have a special generic type parameter constraint to cover unmanaged types, but as it stands, there isn't one in the CLR.

At one point I wrote this article explaining how to do exactly that, but many times faster than the Marshal.PtrToStructure. The code sample uses dynamic code generation to copy the generic type T to/from bit stream.

Assuming:

  • A Sequential or Explicit Structure (otherwise very bad idea)
  • Correct data sizes (you should pre-check & throw)

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

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

You'll have to add a C++/CLI project to your Visual Studio solution though.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!