c#如何将结构体的数组转换为数组的结构体

本文关键字:数组 结构体 转换 | 更新日期: 2023-09-27 18:09:45

我将从发送周期性数据包的硬件源的结构化数据的IntPtr开始。线程从Intptr缓冲区复制数据包,并将byte[]放入队列中。稍后读取队列,并使用此答案将byte[]转换为结构,并成为Packet类型的集合(数组)。

struct Packet {
  long time;
  int field1;
  short field2;
}
Packet[] array_of_packet; 

在不重复结构定义的情况下,我想使用数据,就好像它是一个数组结构。

struct ArrayOfPacket {
  long[] time;
  int[] field1;
  short[] field2;
}
ArrayOfPacket data;  

这种格式允许其他函数使用它们作为向量:

Plot(data.time, data.field1);

c#如何将结构体的数组转换为数组的结构体

如果您想要的只是一个简单的方法来转换成数组,那么只需使用LINQ:

Plot (array_of_packet.Select(p => p.time).ToArray(),
      array_of_packet.Select(p => p.field1).ToArray());

如果你正在寻找一种神奇的方法来重新排列内存中的数据而不需要复制,那么你就不走运了。: -)

使用Linq很容易

data.time = array_of_packet.Select(p => p.time).ToArray();
data.field1 = array_of_packet.Select(p => p.field1).ToArray();
data.field2 = array_of_packet.Select(p => p.field2).ToArray();

虽然你需要设置属性为public

一个更有效的解决方案可能是

var time = new long[array_of_packet.Length];
var field1 = new int[array_of_packet.Length];
var field2 = new short[array_of_packet.Length];
for(int i = 0; i < array_of_packet.Length; i++)
{
    time[i] = array_of_paket[i].time;
    field1[i] = array_of_paket[i].field1;
    field2[i] = array_of_paket[i].field2;
}
data.time = time;
data.field1 = field1;
data.field2 = field2;

您可以创建一个包装器类,它公开一个类似数组的访问器语法:

class ArrayWrapper<T, TField>
{
    Func<T, TField> getField;
    T[] array;
    public ArrayWrapper(T[] array, Func<T, TField> getField)
    {
        this.array = array;
        this.getField = getField;
    }
    public TField this[int index]
    {
        get { return this.getField(this.array[index]);}
    }
}

然后,使用像这样的简单的辅助方法:

ArrayWrapper<T, TField> Wrap<T, TField>(T[] array, Func<T, TField> getField)
{
    return new ArrayWrapper<T, TField>(array, getField);
}

你可以创建一个像这样的对象:

var data = new
{
    time = Wrap(array_of_packet, p => p.time),
    field1 = Wrap(array_of_packet, p => p.field1),
    field2 = Wrap(array_of_packet, p => p.field2)
};

…可以按你想要的方式使用:

Plot(data.time, data.field1);

根据你的具体需要,你可以用多种方式详细说明:

  • 使类实现像IList<TField>这样的接口,以便Plot()可以以一种不知道底层类型的方式编写。(数组已经实现了IList<TField>)
  • 如果性能是一个高优先级,而不是使用委托(Func<,>),你可以添加where T is structArrayWrapper的定义,并让ArrayWrapper接受一个字节偏移作为它的构造函数参数,并做一些unsafe魔术更快地访问字段的数据。