C# 实现不同类型数组集合的更好方法
我正在寻找一种C#中的半通用数据结构,用于存储不同整数和浮点类型的数组。在某些情况下,整数是位字段,其中每个位都同等重要,精度损失是不可容忍的。我发现这很困难,也很混乱,因为我的C型系统和我的C型语言不流利 项目:Ethercat定期数据包到达并转换为一种结构(数据包),并在实验过程中累积为C# 实现不同类型数组集合的更好方法,c#,data-structures,collections,type-systems,typed-arrays,C#,Data Structures,Collections,Type Systems,Typed Arrays,我正在寻找一种C#中的半通用数据结构,用于存储不同整数和浮点类型的数组。在某些情况下,整数是位字段,其中每个位都同等重要,精度损失是不可容忍的。我发现这很困难,也很混乱,因为我的C型系统和我的C型语言不流利 项目:Ethercat定期数据包到达并转换为一种结构(数据包),并在实验过程中累积为Packet[]。来自Packet[]的数据包的每个字段都转换为一个数组 我相信我正在寻找一种将这些数组“包装”为单一类型的方法,以便它们可以成为集合的一部分。包装它们还具有一些其他优点(命名、硬件到SI的比
Packet[]
。来自Packet[]
的数据包的每个字段都转换为一个数组
我相信我正在寻找一种将这些数组“包装”为单一类型的方法,以便它们可以成为集合的一部分。包装它们还具有一些其他优点(命名、硬件到SI的比例因子等),以便于将硬件与以后的实现分离
我最好的“包装器”叫做“DataWrapper”(简化如下),但使用它,我在存储、精度损失、对象使用和代码数量方面做出了令人不安的妥协
在C#中有“更好”的方法吗?我的金标准是在Python中使用list of list或numpy.array实现的简单实现,没有明显的折衷
List<dynamic> array_list = new List<dynamic> { };
public void AddArray(dynamic dynamic_array)
{
this.array_list.Add(dynamic_array);
}
可以使用“object”吗?怎么用?是否可以装箱整个数组,或者每个数组元素必须单独装箱(效率低下)
然而,我看到了很多代码和高级编程技术,本质上是一个列表列表
public class DataWrapper
{
private double[] double_array; // backing with double, but it could if I don't use float
private string name;
private double scale_factor_to_SI;
public DataWrapper(string name, double scale_factor, dynamic dynamic_array)
{
this.name = name;
this.scale_factor_to_SI = scale_factor;
this.double_array = new double[dynamic_array.Length];
for (int cnt = 0; cnt < dynamic_array.Length; cnt++)
{
this.double_array[cnt] = (double)dynamic_array[cnt];
}
}
public void Get(out int[] i_array)
{
i_array = this.double_array.Select(item => (int)item).ToArray();
}
public void Get(out long[] i_array)
{
i_array = this.double_array.Select(item => (long)item).ToArray();
}
public double[] GetSI()
{
return this.double_array.Select(item => this.scale_factor_to_SI * (double)item).ToArray();
}
}
public struct Packet // this is an example packet - the actual packet is much larger and will change over time. I wish to make the change in 1 place not many.
{
public long time_uS;
public Int16 velocity;
public UInt32 status_word;
};
public class example
{
public Packet[] GetArrayofPacketFromHardware()
{
return null;
}
public example() {
Packet[] array_of_packet = GetArrayofPacketFromHardware();
var time_uS = array_of_packet.Select(p => p.time_uS).ToArray();
var velocity = array_of_packet.Select(p => p.velocity).ToArray();
var status_bits = array_of_packet.Select(p => p.status_word).ToArray();
List<DataWrapper> collection = new List<DataWrapper> { };
collection.Add(new DataWrapper("time", 1.0e-6, time_uS));
collection.Add(new DataWrapper("velocity", 1/8192, velocity));
collection.Add(new DataWrapper("status", 1, status_bits));
}
}
公共类数据包装器
{
private double[]double_array;//使用double进行备份,但如果不使用float,则可以
私有字符串名称;
私人双刻度系数;
公共数据包装器(字符串名称、双比例系数、动态数组)
{
this.name=名称;
这个。比例系数=比例系数;
this.double_array=新的double[dynamic_array.Length];
对于(int cnt=0;cnt(int)item.ToArray();
}
public void Get(out long[]i_数组)
{
i_array=this.double_array.Select(item=>(long)item.ToArray();
}
公共双[]GetSI()
{
返回此.double_数组。选择(item=>this.scale_factor_to_SI*(double)item).ToArray();
}
}
public struct Packet//这是一个示例数据包-实际数据包要大得多,并且会随时间而变化。我希望在一个地方做出改变,而不是在很多地方。
{
公众长期关注我们;
公共交通速度;
公共UInt32状态字;
};
公开课范例
{
公共数据包[]GetArrayofPacketFromHardware()
{
返回null;
}
公共示例(){
Packet[]数组_of_Packet=GetArrayofPacketFromHardware();
var-time\u-uS=数据包的数组。选择(p=>p.time\u-uS.ToArray();
var-velocity=数据包的数组。选择(p=>p.velocity).ToArray();
var status_bits=_数据包的数组。选择(p=>p.status_字)。ToArray();
列表集合=新列表{};
添加(新的数据包装(“时间”,1.0e-6,time_-uS));
添加(新的数据包装(“velocity”,1/8192,velocity));
添加(新的数据包装(“状态”,1,状态_位));
}
}
您可以将其视为字节[]列表,并使用位转换器序列化值类型,将值类型转换为字节[],然后使用反向调用将其展开
List<byte[]> dataList = new List<byte[]>();
float v = 1.0424f;
byte[] converted = BitConverter.GetBytes(v);
// put converted into a List<byte[]>
dataList.Add(converted);
// Convert it back again
float z= BitConverter.ToSingle(dataList[0], 0);
List dataList=newlist();
浮球v=1.0424f;
byte[]converted=位转换器.GetBytes(v);
//把转换成一个列表
dataList.Add(已转换);
//再把它换回来
float z=BitConverter.ToSingle(数据列表[0],0);
当C#中需要持续的精度时,浮动将是有问题的。。。时期这是不幸的,因为我们都知道我们多么喜欢精确。但我不认为C#是唯一患有这种疾病的语言。也就是说,我认为有一种方法可以实现你想要的,你的包装是一个好的开始
我不熟悉您正在使用的(第三方库),所以我将坚持提供问题的解决方案
如果您知道要检索的类型,我建议使用byte[]
。通过这种方式,您可以在单个列表中有效地存储3个字节[]
var dataList = new List<byte[]>();
dataList.Add(ConvertUsTime(p.time_US));
dataList.Add(ConvertVelocity(p.velocity));
dataList.Add(ConvertStatus(p.status));
byte[] ConvertToArray(long usTime) {
return BitConverter.GetBytes(usTime);
}
byte[] ConvertVelocity(Int16 velocity) {
return BitConverter.GetBytes(velocity);
}
byte[] ConvertStatus(UInt32 status) {
return BitConverter.GetBytes(status);
}
var dataList=newlist();
添加(ConvertUsTime(p.time_US));
添加(ConvertVelocity(p.velocity));
添加(ConvertStatus(p.status));
字节[]ConvertToArray(长usTime){
返回BitConverter.GetBytes(usTime);
}
字节[]转换速度(Int16速度){
返回BitConverter.GetBytes(速度);
}
字节[]转换状态(UInt32状态){
返回BitConverter.GetBytes(状态);
}
。。。对于更通用的方法:
byte[] ConvertValue<T>(T value) where T : struct {
// we have to test for type of T and can use the TypeCode for switch statement
var typeCode = Type.GetTypeCode(typeof(T));
switch(typeCode) {
case TypeCode.Int64:
return BitConverter.GetBytes((long)value);
case TypeCode.Int16:
return BitConverter.GetBytes((Int16)value);
case TypeCode.UInt32:
return BitConverter.GetBytes((UInt32)value);
}
return null;
}
byte[]ConvertValue(T值),其中T:struct{
//我们必须测试T的类型,并且可以使用转换语句的类型代码
var typeCode=Type.GetTypeCode(typeof(T));
开关(类型代码){
case TypeCode.Int64:
返回BitConverter.GetBytes((长)值);
case TypeCode.Int16:
返回BitConverter.GetBytes((Int16)值);
案例类型代码.UInt32:
返回BitConverter.GetBytes((UInt32)值);
}
返回null;
}
您能简单地将数据序列化为JSON或MessagePack并将其存储为字符串数组吗?似乎这将是相对简单的实现和易于使用。作为通用列表方法的反例,我想提到的是,问题中链接的列表示例不应被视为高级。它使用了一个简单的C#接口
当您希望调试列表的内容或希望调试列表上的业务逻辑时,使用实现相同接口的不同类型可能是更好的解决方案
List<dynamic> array_list = new List<dynamic> { };
public void AddArray(dynamic dynamic_array)
{
this.array_list.Add(dynamic_array);
}
int ndx = 0;
foreach (var array_from_list in this.array_list) {
var v = array_from_list[ndx]; // error if array_from_list is ArrayList
}
using System;
using System.Collections.Generic;
namespace Application
{
class MyTest
{
List<dynamic> array_list = new List<dynamic> { };
int length;
public void AddArray(dynamic dynamic_array)
{
this.array_list.Add(dynamic_array);
this.length = dynamic_array.Length;
}
public dynamic GetVector(int ndx)
{
return array_list[ndx];
}
public void Display()
{
for (int ndx = 0; ndx < this.length; ndx++)
{
string ln_txt = "";
foreach (var array_from_list in this.array_list)
{
string s = array_from_list[ndx].ToString();
ln_txt += $"{s} ";
}
Console.WriteLine(ln_txt);
}
}
}
static class Program
{
[STAThread]
static void Main(string[] args)
{
MyTest test = new MyTest();
test.AddArray(new long[] { 10, 20, 30, 40 });
test.AddArray(new int[] { 1, 2, 3, 4 });
test.AddArray(new double[] { .1, .2, .3, .4 });
test.AddArray(new string[] { "a", "b", "c", "d" });
test.Display();
for (int vecnum = 0; vecnum < 4; vecnum++)
{
var vector = test.GetVector(vecnum);
Console.Write($"vnum:{vecnum} : ");
foreach (var value in vector)
{
Console.Write($"{value} ");
}
Console.WriteLine("");
}
}
}
}