Punteros de tipo genérico? y la matriz de bytes de conversión a un tipo dado de genérico?

Bueno, la idea básica de lo que estoy tratando de hacer es convertir el conjunto de bytes en algo como corto o int, etc., etc.

Un ejemplo simple podría ser:

unsafe { fixed (byte* byteArray = new byte[5] { 255, 255, 255, 126, 34 }) { short shortSingle = *(short*)byteArray; MessageBox.Show((shortSingle).ToString()); // works fine output is -1 } } 

Bien, lo que realmente estoy tratando de hacer es hacer una extensión a la clase Stream; Métodos extendidos de lectura y escritura. Necesito ayuda en el siguiente código:

 unsafe public static T Read(this Stream stream) { int bytesToRead = sizeof(T); // ERROR: Cannot take the address of, get the size of, or declare a pointer to a managed type ('T') byte[] buffer = new byte[bytesToRead]; if (bytesToRead != stream.Read(buffer, 0, bytesToRead)) { throw new Exception(); } fixed (byte* byteArray = buffer) { T typeSingle = *(T*)byteArray; // ERROR: Cannot take the address of, get the size of, or declare a pointer to a managed type ('T') return typeSingle; } } unsafe public static T[] Read(this Stream stream, int count) { // haven't figured out it yet. This is where I read and return T arrays } 

Siento que tengo que usar los punteros para la velocidad porque estaré trabajando para escribir y leer datos de secuencias como las clases de NetworkStream. ¡Gracias por tu ayuda!

EDITAR:

Y mientras trato de averiguar cómo puedo devolver arrays T, me he enfrentado a este problema:

 unsafe { fixed (byte* byteArray = new byte[5] { 0, 0, 255, 255, 34 }) { short* shortArray = (short*)byteArray; MessageBox.Show((shortArray[0]).ToString()); // works fine output is 0 MessageBox.Show((shortArray[1]).ToString()); // works fine output is -1 short[] managedShortArray = new short[2]; managedShortArray = shortArray; // The problem is, How may I convert pointer to a managed short array? ERROR: Cannot implicitly convert type 'short*' to 'short[]' } } 

EL RESUMEN: Tengo que convertir de una matriz de bytes a un tipo dado de T OR a un tipo dado de matriz T con una longitud dada

No puede hacer que esta función sea genérica debido a las restricciones de puntero en C #. Cualquiera de los siguientes tipos puede ser un tipo de puntero:

  • sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal o bool.
  • Cualquier tipo de enumeración.
  • Cualquier tipo de puntero.
  • Cualquier tipo de estructura definida por el usuario que contenga campos de tipos no administrados solamente.

Pero no puede establecer una restricción en T where T . where T : struct está muy cerca, pero no lo suficiente, porque las estructuras definidas por el usuario pueden contener campos de tipos de referencia.

Existe una solución alternativa: System.Runtime.InteropServices.Marshal.PtrToStructure() (simplemente lanza una excepción si no puede trabajar con el tipo de objeto especificado), pero también eliminaría cualquier mejora de rendimiento lograda.

Creo que la única forma de hacerlo es crear funciones no genéricas para todos los tipos deseados.

Edición: restricción unmanaged agregada a C # 7.3 .

Saltando un poco tarde en este caso, pero con C # 7.3 viene la adición de la restricción de tipo unmanaged .

Con la restricción de tipo no administrado, puede usar punteros generics ( T* ) entre otras cosas, siempre que el tipo que se pasa no esté administrado.

Probé el método genérico que proporcionaste, y funciona ahora. Además, puede extenderlo para devolver una matriz como tal:

 public static unsafe T[] ReadAsArray(this Stream stream) where T : unmanaged { var length = stream.Length; var returnArray = new T[length]; for (var i = 0; i < length; i++) { int bytesToRead = sizeof(T); // no longer throws error byte[] buffer = new byte[bytesToRead]; if (bytesToRead != stream.Read(buffer, 0, bytesToRead)) { throw new Exception(); } fixed (byte* byteArray = buffer) { T typeSingle = *(T*)byteArray; // no longer throws error returnArray[i] = typeSingle; } } return returnArray; } 

Puede llamarlo con el siguiente código, que imprimirá el contenido de un archivo:

 using (var sourceStream = File.Open(filename, FileMode.Open)) { var byteArray = sourceStream.ReadAsArray(); Console.Write(new string(byteArray.Select(b => (char)b).ToArray())); }