Common type pointers? and casting a byte array into a given common type?

Well, the main idea that I'm trying to do is convert a byte array into something like a short or integer, etc. etc.

A simple example would be:

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

Okay, so what I'm really trying to do is make an extension for the Stream class; advanced read and write methods. I need help with the following code:

 unsafe public static T Read<T>(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<T>(this Stream stream, int count) { // haven't figured out it yet. This is where I read and return T arrays } 

It seems to me that I should use pointers for speed, because I will work on writing and reading data from streams, such as NetworkStream classes. Thank you for your help!

EDIT:

And although I am trying to figure out how to return T-arrays, I ran into this problem:

 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[]' } } 

SUMMARY: I need to convert from a byte array to a given type T OR a given type of array T with a given length

+8
c #
source share
2 answers

You cannot make this function generalized due to limitations of a pointer to C #. Any of the following types can be a pointer type:

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

But you cannot set a restriction on T where T <can be pointer type> . where T : struct very close, but not enough, because custom structures can contain fields of reference types.

The workaround is System.Runtime.InteropServices.Marshal.PtrToStructure() (it just throws an exception if it cannot work with the specified type of object), but it will also kill any performance improvements achieved.

I think the only way to do this is to create non-generic functions for all the desired types.

+5
source share

Change: unmanaged restriction added in C # 7.3 .

Jumping a little late on this, but with C # 7.3, an addition of unmanaged type constraint appears.

With an unmanaged type restriction, you can use generic pointers ( T* ), among other things, provided that the passed type is unmanaged.

I tested the general method you provided and it works now. Alternatively, you can expand it to return an array as follows:

 public static unsafe T[] ReadAsArray<T>(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; } 

You can call it with the following code that prints the contents of the file:

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

All Articles