2009-09-21 1 views
4

Недавно я столкнулся с ситуацией, когда мне нужно создать общий метод для чтения типа данных из байтового массива.Общий метод BitConverter?

Я создал следующий класс:


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

Теперь вопросы де-распределения в сторону, этот код не компилируется с этим сообщением:

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

, которая, кажется странным, потому что вы должен иметь возможность выполнять вышеуказанные операции на основе ограничения where T : struct на метод.

Если этот код ужасно некорректен, есть ли простой способ взять серию байтов и ввести их в тип 'T'?

Спасибо!

ответ

8

Вместо того чтобы пытаться это сделать с помощью манипуляции с указателем, вы должны переключить свой код на использование Mashal.PtrToStructure. Этот метод специально разработан для этого сценария.

+0

спасибо для быстрого ответа это было именно то, что я искал! –

+0

Может ли кто-нибудь из вас разработать (отправить код)? –

7

Поскольку ответ уже дан, позвольте мне объяснить, почему исходный код не работает для вас:

, которая, кажется странным, потому что вы должны быть в состоянии сделать вышеуказанные операции основаны на где T: ограничение структуры для метода.

Не совсем. У вас могут быть необработанные указатели на неуправляемые типы. Это определяется следующим образом в C# языка спецификации (18.2):

В отличие от ссылок (значений ссылочных типов), указатели не отслеживаются сборщиком мусора - сборщик мусора не имеет знание указателей и данные которые они указывают. По этой причине указателю не разрешается указывать ссылку или структуру, содержащую ссылки, а тип референта указателя должен быть неуправляемым типом. неуправляемый тип - это любой тип, который не является ссылочным, и не содержит полей ссылочного типа на любом уровне вложенности. Другими словами, неуправляемого типа является одним из следующих действий:

  • sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal или bool.
  • Любые enum-type.
  • Любой Указатель типа.
  • Любой пользовательский struct-type, который содержит поля неуправляемых типов.

Таким образом, существует довольно много ограничений, и для общего метода, T:struct может или не соответствовать им для любого конкретного экземпляра, поэтому построить как T* является незаконным. Было бы неплохо иметь специальное ограничение типа типового типа для охвата неуправляемых типов, но, как оно есть, в CLR нет ни одного.

+0

А я вижу. Я никогда не думал, что ограничение структуры может потенциально позволить другим типам управляемых типов в микс. Спасибо за объяснение! –

2

В какой-то момент я написал this article, объясняя, как это сделать точно, но во много раз быстрее, чем у Marshal.PtrToStructure. В примере кода используется генерация динамического кода для копирования генерируемого типа T в/из битового потока.

1

Предполагая:

  • последовательного или Явный структуры (в противном случае очень плохая идея)
  • Правильные размеры данных (вы должны предварительно проверить & бросок)

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

Это лучшие и самые компактные решения, которые я когда-либо видел. Я начал использовать их, и они действительно полезны. – MrHIDEn

 Смежные вопросы

  • Нет связанных вопросов^_^