user3689186
user3689186

Reputation: 148

In C#, is it possible to cast a byte array into another type without creating a new array?

I have a byte[] object that I'm using as a data buffer.

I want to "read" it as an array of a either primitive/non-primitive structs without duplicating the byte[] data in memory.

The goal would be something like:

byte[] myBuffer;

//Buffer is populated

int[] asInts = PixieDust_ToInt(myBuffer);
MyStruct[] asMyStructs = PixieDust_ToMyStruct(myBuffer);

Is this possible? If so, how?

Upvotes: 3

Views: 2593

Answers (4)

Timo
Timo

Reputation: 8680

Is it possible? Practically, yes!

Since .NET Core 2.1, MemoryMarshal lets us do this for spans. If you are satisfied with a span instead of an array, then yes.

var intSpan = MemoryMarshal.Cast<byte, int>(myByteArray.AsSpan());

The int span will contain byteCount / 4 integers.

As for custom structs... The documentation claims to require a "primitive type" on both sides of the conversion. However, you might try using a ref struct and see that is the actual constraint. I wouldn't be surprised if it worked!

Note that ref structs are still very limiting, but the limitation makes sense for the kind of reinterpret casts that we are talking about.

Edit: Wow, the constraint is much less strict. It requires any struct, rather than a primitive. It does not even have to be a ref struct. There is only a runtime check that will throw if your struct contains a reference type anywhere in its hierarchy. That makes sense. So this should work for your custom structs as well as it does for ints. Enjoy!

Upvotes: 6

Harald Coppoolse
Harald Coppoolse

Reputation: 30454

Consider class System.BitConverter

This class has functions to reinterpret the bytes starting at a given index as an Int32, Int64, Double, Boolean, etc. and back from those types into a sequence of bytes.

Example:

int32 x = 0x12345678;
var xBytes = BitConverter.GetBytes(x);
// bytes is a byte array with length 4: 0x78; 0x56; 0x34; 0x12
var backToInt32 = BitConverter.ToInt32(xBytes, 0);

Or if your array contains mixed data:

double d = 3.1415;
int16 n = 42;
Bool b = true;
Uint64 u = 0xFEDCBA9876543210;

// to array of bytes:
var dBytes = BitConverter.GetBytes(d);
var nBytes = BitConverter.GetBytes(n);
var bBytes = BitConverter.GetBytes(b);
var uBytes = BitConterter.GetBytes(u);
Byte[] myBytes = dBytes.Concat(nBytes).Concat(bBytes).Concat(uBytes).ToArray();

// startIndexes in myBytes:
int startIndexD = 0;
int startIndexN = dBytes.Count();
int startIndexB = startIndexN + nBytes.Count();
int startIndexU = startIndexB + bBytes.Count();

// back to original elements
double dRestored = Bitconverter.ToDouble(myBytes, startIndexD);
int16 nRestored = BitConverter.ToInt16(myBytes, startIndexN);
bool bRestored = BitConverter.ToBool(myBytes, startIndexB);
Uint64 uRestored = BitConverter.ToUint64(myBytes, startIndexU);

Upvotes: 1

Benj
Benj

Reputation: 989

The closest you will get in order to convert a byte[] to other base-types is

Byte[] b = GetByteArray();

using(BinaryReader r = new BinaryReader(new MemoryStream(b)))
{
    r.ReadInt32();
    r.ReadDouble();
    r.Read...();
}

There is however no simple way to convert a byte[] to any kind of object[]

Upvotes: 0

Servy
Servy

Reputation: 203821

You will not be able to do this. To have a MyStruct[] you'll need to actually create such an array of that type and copy the data over. You could, in theory, create your own custom type that acted as a collection, but was actually just a facade over the byte[], copying the bytes out into the struct objects as a given value was accessed, but if you end up actually accessing all of the values, this would end up copying all of the same data eventually, it would just potentially allow you to defer it a bit and may be helpful if you only actually use a small number of the values.

Upvotes: 1

Related Questions