说我有一个字节集合
var bytes = new byte[] {0, 1, 2, 3, 4, 5, 6, 7};
我希望从字节中提取一个定义的值作为托管类型,例如一个ushort
。什么是一种简单的方法来定义哪些类型驻留在集合中的哪个位置并提取这些值?
一种(丑陋)方式是将System.BitConverter
和Queue
或byte[]
与索引一起使用,并简单地遍历,例如:
int index = 0;
ushort first = System.BitConverter.ToUint16(bytes, index);
index += 2; // size of a ushort
int second = System.BitConverter.ToInt32(bytes, index);
index += 4;
...
当你处理很多这些结构时,这种方法变得非常繁琐!
我知道有System.Runtime.InteropServices.StructLayoutAttribute
允许我在结构或类中定义类型的位置,但似乎没有办法将字节集合导入到该结构中。如果我能以某种方式将结构覆盖在字节集合上并拉出值,那将是理想的。 E.g。
Foo foo = (Foo)bytes; // doesn't work because I'd need to implement the implicit operator
ushort first = foo.first;
int second = foo.second;
...
[StructLayout(LayoutKind.Explicit, Size=FOO_SIZE)]
public struct Foo {
[FieldOffset(0)] public ushort first;
[FieldOffset(2)] public int second;
}
有关如何实现这一目标的任何想法?
[编辑:另见我的question on how to deal with the bytes when they are big endian。]
答案 0 :(得分:1)
我们已经做了很多工作,因为我们通过串行字节直接与硬件对话。
给出结构定义
[StructLayout(LayoutKind.Explicit, Size=FOO_SIZE)]
public struct Foo {
[FieldOffset(0)] public ushort first;
[FieldOffset(2)] public int second;
}
您可以使用这样的类来执行转换
public class ByteArrayToStruct<StructType>
{
public StructType ConvertToStruct(int size, byte[] thebuffer)
{
try
{
int theSize = size;
IntPtr ptr1 = Marshal.AllocHGlobal(theSize);
Marshal.Copy(thebuffer, 0, ptr1, theSize);
StructType theStruct = (StructType)Marshal.PtrToStructure(ptr1, typeof(StructType));
Marshal.FreeHGlobal(ptr1);
return theStruct;
}
catch (Exception)
{
return default(StructType);
}
}
}
相反,您也可以从数组中创建List并执行以下操作:
ushort first = BitConverter.ToInt16(myList.ToArray(), 0);
myList.RemoveRange(0, sizeof(ushort));
[...]
这实际上是将相关数据保存在列表的“头部”,因此您不必跟踪数组中的位置。
答案 1 :(得分:0)
第一种方式。定义一个具有数据字节和游标的Buffer类。然后定义getInt16,getInt32等方法。然后你去
Buffer b(bytes);
ushort a = b.getInt16();
int x = b.getInt32();
我在我的工具包里有这个。我也有相反的意思,用ints字符串创建缓冲区,....