在C#中,是否可以在不创建新数组的情况下将字节数组转换为另一种类型?

时间:2016-10-18 13:47:40

标签: c# arrays memory-management casting

我有一个byte []对象,我将其用作数据缓冲区。

我希望将它“读取”为原始/非原始结构的数组,而不会复制内存中的byte []数据。

目标如下:

byte[] myBuffer;

//Buffer is populated

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

这可能吗?如果是这样,怎么样?

4 个答案:

答案 0 :(得分:1)

你将无法做到这一点。要拥有MyStruct[],您需要实际创建此类型的数组并复制数据。理论上,您可以创建自己的自定义类型作为集合,但实际上只是byte[]上的一个外观,在访问给定值时将字节复制到struct对象中,但如果你最终实际访问了所有的值,最终会最终复制所有相同的数据,它可能会让你推迟一点,如果你只实际使用少量的值可能会有所帮助

答案 1 :(得分:1)

有可能吗?实际上,是的!

自.NET Core 2.1开始,MemoryMarshal使我们可以跨度执行此操作。如果您对跨度而不是数组感到满意,那么可以。

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

int跨度将包含byteCount / 4个整数。

关于自定义结构...文档声称转换的两面都需要“原始类型”。但是,您可以尝试使用ref struct并看到这是 actual 约束。如果有效的话,我不会感到惊讶!

请注意,引用结构仍然非常受限制,但是这种限制对于我们正在谈论的重新解释类型转换是有意义的。

编辑:哇,约束要严格得多。它需要任何结构,而不是基元。它甚至不必是ref struct。如果您的结构在其层次结构中的任何位置包含引用类型,则只会抛出 runtime 检查。那讲得通。因此,这应该适用于您的自定义结构以及适用于int的结构。享受吧!

答案 2 :(得分:0)

为了将byte []转换为其他基本类型,您将获得的最接近的是

Byte[] b = GetByteArray();

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

然而,没有简单的方法将byte []转换为任何类型的对象[]

答案 3 :(得分:0)

考虑班级System.BitConverter

此类具有将从给定索引开始的字节重新解释为Int32,Int64,Double,Boolean等的函数,并从这些类型返回到字节序列。

示例:

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

或者,如果您的数组包含混合数据:

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