C# 在C语言中将字节数组转换为枚举集合
我有一个字节数组,它从函数GetData以小字节顺序接收枚举,我想将数组转换为枚举的集合。 如何将字节按LE顺序复制并强制转换为C中的枚举值?我有C++背景,对语言不太熟悉。 这是一个示例代码段:C# 在C语言中将字节数组转换为枚举集合,c#,casting,endianness,C#,Casting,Endianness,我有一个字节数组,它从函数GetData以小字节顺序接收枚举,我想将数组转换为枚举的集合。 如何将字节按LE顺序复制并强制转换为C中的枚举值?我有C++背景,对语言不太熟悉。 这是一个示例代码段: public enum BarID { TAG0 = 0x0B01, TAG1 = 0x0B02, } public class TestClass { List<BarID> ids; internal TestClass() { ids = new
public enum BarID
{
TAG0 = 0x0B01,
TAG1 = 0x0B02,
}
public class TestClass
{
List<BarID> ids;
internal TestClass()
{
ids = new List<BarID>();
byte[] foo = GetData(); // returns 01 0b 00 00 02 0b 00 00
// cast byte array so that ids contains the enums 'TAG0' and 'TAG1'
}
}
不清楚数组值是按两个还是四个分组,但模式基本相同:
public enum BarID
{
TAG0 = 0x0B01,
TAG1 = 0x0B02,
}
public class TestClass
{
List<BarID> ids;
internal TestClass()
{
ids = new List<BarID>();
byte[] foo = GetData(); // returns 01 0b 00 00 02 0b 00 00
// cast byte array so that ids contains the enums 'TAG0' and 'TAG1'
//create a hash-set with all the enum-valid values
var set = new HashSet<int>(
Enum.GetValues(typeof(BarID)).OfType<int>()
);
//scan the array by 2-bytes
for (int i = 0; i < foo.Length; i += 2)
{
int value = foo[i] + foo[i + 1] << 8;
if (set.Contains(value))
{
ids.Add((BarID)value);
}
}
}
}
该集合不是强制性的,但它应该防止将无效值强制转换为标记。例如,如果值是基于字的,则00值无效
最后,我不会在类构造函数中执行类似的任务:最好创建实例,然后调用专用方法进行转换。不清楚数组值是否按两个或四个分组,但是模式基本相同:
public enum BarID
{
TAG0 = 0x0B01,
TAG1 = 0x0B02,
}
public class TestClass
{
List<BarID> ids;
internal TestClass()
{
ids = new List<BarID>();
byte[] foo = GetData(); // returns 01 0b 00 00 02 0b 00 00
// cast byte array so that ids contains the enums 'TAG0' and 'TAG1'
//create a hash-set with all the enum-valid values
var set = new HashSet<int>(
Enum.GetValues(typeof(BarID)).OfType<int>()
);
//scan the array by 2-bytes
for (int i = 0; i < foo.Length; i += 2)
{
int value = foo[i] + foo[i + 1] << 8;
if (set.Contains(value))
{
ids.Add((BarID)value);
}
}
}
}
该集合不是强制性的,但它应该防止将无效值强制转换为标记。例如,如果值是基于字的,则00值无效
最后,我不会在类构造函数中执行类似的任务:最好创建实例,然后调用专用方法进行转换。尝试以下操作:
var foo = new byte[] {0x01, 0x0b, 0x00, 0x00, 0x02, 0x0b, 0x00, 0x00}.ToList();
IEnumerable<byte> bytes;
var result = new List<BarID>();
while ((bytes = foo.Take(4)).Any())
{
var number = BitConverter.IsLittleEndian
? BitConverter.ToInt32(bytes.ToArray(), 0)
: BitConverter.ToInt32(bytes.Reverse().ToArray(), 0);
var enumValue = (BarID) number;
result.Add(enumValue);
foo = foo.Skip(4).ToList();
}
试试这个:
var foo = new byte[] {0x01, 0x0b, 0x00, 0x00, 0x02, 0x0b, 0x00, 0x00}.ToList();
IEnumerable<byte> bytes;
var result = new List<BarID>();
while ((bytes = foo.Take(4)).Any())
{
var number = BitConverter.IsLittleEndian
? BitConverter.ToInt32(bytes.ToArray(), 0)
: BitConverter.ToInt32(bytes.Reverse().ToArray(), 0);
var enumValue = (BarID) number;
result.Add(enumValue);
foo = foo.Skip(4).ToList();
}
这里有趣的一步是以小尾端的方式可靠地读取字节,这里的可靠意味着可以在任何CPU上工作,而不仅仅是碰巧是小尾端本身的CPU;幸运的是,BinaryPrimitives使这一点变得显而易见,它给您一个Span中的int,GetData中的byte[]可以隐式地转换为Span。然后从int开始,您可以将其转换为BarID: Span foo=GetData; var结果=新巴里德[foo.Length/4]; 对于int i=0;i
为什么不用字典呢?您可以将KeyValuePairs存储到一起。在循环中,BarIDBitConverter.ToInt32foo,[pos];,其中[pos]=0,4,…@Jimi如果我在32位系统上,这会有什么变化吗?枚举的大小会不同吗?不,是相同的大小。但是,看看Marc Gravell写的。BitConverter.IsLittleEndiant这是不可靠的-它是CPU端;它也像任何东西一样分配,现在它在big-endian架构上分配得更多,至少:这是不可靠的-它是CPU-endian;它也像任何东西一样进行分配,现在它在big-endian体系结构上的分配甚至更多,至少:这比Tomas的答案有效得多,尽管它只在.NET内核或.NET标准2.1上工作。@GyörgyKőszeg不,这是错误的;从.NET 4.5/.NET Standard 1.1/到其他各种版本,它在任何地方都能工作-你只需要啊,你毕竟是对的,我的意思是不允许使用nuget软件包。@GyörgyKőszeg嗯,是的,但既然这是.NET中事实上的分发机制,不允许nuget软件包是非常愚蠢的:用愚蠢的方式做事:这比Tomas的答案有效得多,尽管它只在.NET内核或.NET标准2.1上有效。@GyörgyKőszeg不,这是错误的;从.NET 4.5/.NET Standard 1.1/到其他各种版本,它在任何地方都能工作-你只需要啊,你毕竟是对的,我的意思是不允许使用nuget软件包。@GyörgyKőszeg嗯,是的,但既然这是.NET中事实上的分发机制,禁止nuget软件包非常愚蠢:用愚蠢的方式做事:尽管Marc的答案既好又快,但这只适用于.NETCore这是完全错误的,;它几乎可以在任何地方工作,包括.NETFramework到4.5:-您只需要一个对系统的包引用。内存:答案已更正。也许这只是我的错,我不喜欢在我的库中添加许多第三方依赖项,这样它们只支持从.NET Core 3/Standard 2.1开始的Span及其朋友,尽管Marc的答案既好又快,但这只适用于.NET Core。-这是完全错误的,;它几乎可以在任何地方工作,包括.NETFramework到4.5:-您只需要一个对系统的包引用。内存:答案已更正。也许这只是我的错,我不喜欢在我的库中添加很多第三方依赖项,所以它们只支持从.NET Core 3/Standard 2.1开始的Span及其朋友