我认为.NET有一种简单的转换方法,可以将int类型转换为byte数组?我进行了快速搜索,发现所有的解决方案都是逐个字节进行位掩码 / 移位操作,就像“好旧的日子”一样。 难道没有ToByteArray()方法吗?
2020年更新 - 现在应该优先使用BinaryPrimitives
而不是BitConverter
。它提供了特定于字节序的API,并且分配更少的内存。
byte[] bytes = BitConverter.GetBytes(i);
需要注意的是,你可能需要检查BitConverter.IsLittleEndian
来确定字节序列的顺序!
如果你需要频繁地进行此操作,你可能希望避免所有这些短暂的数组分配,并通过位移运算(>>
/ <<
)或者使用不安全代码自己编写。位移运算还具有一个优点,它们不受您平台的字节序影响,你总是能按照预期的顺序获得字节。
马克的回答当然是正确的。但由于他提到移位运算符和不安全代码作为替代方案,我想分享一个不太常见的替代方案。使用带有 Explicit
布局的结构体。这在原理上类似于 C/C++ 中的 union
。
以下是一个示例结构体,可用于获取 Int32 数据类型的组件字节,好处是它是双向的,可以操纵字节值并查看对 Int 的影响。
using System.Runtime.InteropServices;
[StructLayout(LayoutKind.Explicit)]
struct Int32Converter
{
[FieldOffset(0)] public int Value;
[FieldOffset(0)] public byte Byte1;
[FieldOffset(1)] public byte Byte2;
[FieldOffset(2)] public byte Byte3;
[FieldOffset(3)] public byte Byte4;
public Int32Converter(int value)
{
Byte1 = Byte2 = Byte3 = Byte4 = 0;
Value = value;
}
public static implicit operator Int32(Int32Converter value)
{
return value.Value;
}
public static implicit operator Int32Converter(int value)
{
return new Int32Converter(value);
}
}
现在可以按以下方式使用上述内容
Int32Converter i32 = 256;
Console.WriteLine(i32.Byte1);
Console.WriteLine(i32.Byte2);
Console.WriteLine(i32.Byte3);
Console.WriteLine(i32.Byte4);
i32.Byte2 = 2;
Console.WriteLine(i32.Value);
当然,不可变性警察可能对最后一种可能性不感兴趣 :)
这可能与主题无关,但如果您需要序列化大量的原始类型或POD结构,则Google Protocol Buffers for .Net可能对您有用。这解决了Marc提到的字节序问题,以及其他一些有用的功能。
如果您从谷歌来到这里
对于旧问题的替代答案提到了John Skeet的库,该库具有让您直接将原始数据类型写入带有索引偏移量的byte[]的工具。如果需要性能,则远比BitConverter
更好。
只需下载源代码并查看MiscUtil.Conversion
命名空间。 EndianBitConverter.cs
会为您处理所有内容。
使用MemoryMarshal和Span进行堆分配释放
int messageLen = 1111;
Span<byte> messageTypeBytes = MemoryMarshal.AsBytes(MemoryMarshal.CreateSpan(ref messageLen, 1));
BenchmarkDotnet
| Method | Mean | Error | StdDev | Allocated |
|------------------ |----------:|----------:|----------:|----------:|
| MemoryMarshalTest | 0.0023 ns | 0.0017 ns | 0.0014 ns | - |
这里的大多数答案要么是“不安全”的,要么不支持LittleEndian。BitConverter不支持LittleEndian。 因此,在here的示例基础上(请参见PZahra发布的帖子),当BitConverter.IsLittleEndian == true时,我通过反向读取字节数组来制作了一个LittleEndian安全版本。
void Main(){
Console.WriteLine(BitConverter.IsLittleEndian);
byte[] bytes = BitConverter.GetBytes(0xdcbaabcdfffe1608);
//Console.WriteLine(bytes);
string hexStr = ByteArrayToHex(bytes);
Console.WriteLine(hexStr);
}
public static string ByteArrayToHex(byte[] data)
{
char[] c = new char[data.Length * 2];
byte b;
if(BitConverter.IsLittleEndian)
{
//read the byte array in reverse
for (int y = data.Length -1, x = 0; y >= 0; --y, ++x)
{
b = ((byte)(data[y] >> 4));
c[x] = (char)(b > 9 ? b + 0x37 : b + 0x30);
b = ((byte)(data[y] & 0xF));
c[++x] = (char)(b > 9 ? b + 0x37 : b + 0x30);
}
}
else
{
for (int y = 0, x = 0; y < data.Length; ++y, ++x)
{
b = ((byte)(data[y] >> 4));
c[x] = (char)(b > 9 ? b + 0x37 : b + 0x30);
b = ((byte)(data[y] & 0xF));
c[++x] = (char)(b > 9 ? b + 0x37 : b + 0x30);
}
}
return String.Concat("0x",new string(c));
}
它返回这个:
True
0xDCBAABCDFFFE1608
这是进入字节数组的确切十六进制。
BitConverter.GetBytes(250)
返回[250,0,0,0]
而不是[250]
?Byte.MaxValue == 255
,对吗? - user4584267unsafe
- 但具体取决于您要做什么 - 最好的方法是实现两次并测试其中的1000万个,对它们进行计时。 - Marc Gravell