我的.NET应用程序中有大量的3D数组。我需要将它们转换为1D数组以将其传递给COM库。有没有办法转换数组而不复制所有数据?
我可以像这样进行转换,但后来我使用了两倍的内存量,这在我的应用程序中是一个问题:
double[] result = new double[input.GetLength(0) * input.GetLength(1) * input.GetLength(2)];
for (i = 0; i < input.GetLength(0); i++)
for (j = 0; j < input.GetLength(1); j++)
for (k = 0; k < input.GetLength(2); k++)
result[i * input.GetLength(1) * input.GetLength(2) + j * input.GetLength(2) + k)] = input[i,j,l];
return result;
答案 0 :(得分:8)
我不相信C#将数据存储在内存中的方式会使其与C中的简单转换相同。为什么不使用1d数组开始,也许为类型创建一个类,这样你就可以在你的程序中访问它,好像它是一个3d数组?
答案 1 :(得分:6)
不幸的是,C#数组不能保证在连续的内存中,就像它们使用更接近金属的语言一样。所以,不。如果没有逐个元素的复制,就无法将double [,,]转换为double []。
答案 2 :(得分:3)
考虑使用Proxy抽象对数据的访问(类似于C ++中的迭代器/智能指针)。不幸的是,语法不像C ++那样干净,因为operator()不能用于重载,而operator []是单arg,但仍然很接近。
当然,这种额外的抽象级别会增加其自身的复杂性和工作量,但它允许您对使用双[,,]对象的现有代码进行最小的更改,同时允许您使用单个double []互操作和你的in-C#计算的数组。
class Matrix3
{
// referece-to-element object
public struct Matrix3Elem{
private Matrix3Impl impl;
private uint dim0, dim1, dim2;
// other constructors
Matrix3Elem(Matrix3Impl impl_, uint dim0_, uint dim1_, uint dim2_) {
impl = impl_; dim0 = dim0_; dim1 = dim1_; dim2 = dim2_;
}
public double Value{
get { return impl.GetAt(dim0,dim1,dim2); }
set { impl.SetAt(dim0, dim1, dim2, value); }
}
}
// implementation object
internal class Matrix3Impl
{
private double[] data;
uint dsize0, dsize1, dsize2; // dimension sizes
// .. Resize()
public double GetAt(uint dim0, uint dim1, uint dim2) {
// .. check bounds
return data[ (dim2 * dsize1 + dim1) * dsize0 + dim0 ];
}
public void SetAt(uint dim0, uint dim1, uint dim2, double value) {
// .. check bounds
data[ (dim2 * dsize1 + dim1) * dsize0 + dim0 ] = value;
}
}
private Matrix3Impl impl;
public Matrix3Elem Elem(uint dim0, uint dim1, uint dim2){
return new Matrix2Elem(dim0, dim1, dim2);
}
// .. Resize
// .. GetLength0(), GetLength1(), GetLength1()
}
然后使用这种类型进行读写 - 'foo [1,2,3]'现在写成'foo.Elem(1,2,3).Value',同时读取值和写入值,在赋值和值表达式的左侧。
void normalize(Matrix3 m){
double s = 0;
for (i = 0; i < input.GetLength0; i++)
for (j = 0; j < input.GetLength(1); j++)
for (k = 0; k < input.GetLength(2); k++)
{
s += m.Elem(i,j,k).Value;
}
for (i = 0; i < input.GetLength0; i++)
for (j = 0; j < input.GetLength(1); j++)
for (k = 0; k < input.GetLength(2); k++)
{
m.Elem(i,j,k).Value /= s;
}
}
同样,增加了开发成本,但共享数据,消除了复制开销和复制相关的开发成本。这是一个权衡。
答案 3 :(得分:1)
如果不知道COM库的详细信息,我会考虑在.Net中创建一个Facade类,并在必要时将其公开给COM。
你的外观需要一个双[,,]并有一个索引器,将从[]到[,,]。
编辑:我同意评论中提出的观点,Lorens建议更好。
答案 4 :(得分:1)
作为一种解决方法,您可以创建一个以一维形式维护数组的类(甚至可以更接近裸机形式,以便您可以轻松地将其传递给COM库?)然后在此类上重载operator []使其可用作C#代码中的多维数组。