适应二维情况的包装类

这个问题是这个问题的延伸。

我想适应二维情况的包装。 这是我的第一次尝试:

public class EmxArrayRealTWrapper : IDisposable { private readonly emxArray_real_T _value; private GCHandle _dataHandle; private GCHandle _sizeHandle; public emxArray_real_T Value { get { return _value; } } public EmxArrayRealTWrapper(double[,] data) { _dataHandle = GCHandle.Alloc(data, GCHandleType.Pinned); _value.data = _dataHandle.AddrOfPinnedObject(); _sizeHandle = GCHandle.Alloc(new int[] { data.GetLength(0), data.GetLength(1) }, GCHandleType.Pinned); _value.size = _sizeHandle.AddrOfPinnedObject(); _value.allocatedSize = data.GetLength(0) * data.GetLength(1) * sizeof(double); _value.numDimensions = 2; _value.canFreeData = false; } public void Dispose() { _dataHandle.Free(); _sizeHandle.Free(); GC.SuppressFinalize(this); } ~EmxArrayRealTWrapper() { Dispose(); } } [StructLayout(LayoutKind.Sequential)] public struct emxArray_real_T { public IntPtr data; public IntPtr size; public int allocatedSize; public int numDimensions; [MarshalAs(UnmanagedType.U1)] public bool canFreeData; } 

PS:

原始的matlab代码如下所示:

  function [x] = test(a) %#codegen x = 0; if(~isempty(coder.target)) assert(isa(a,'double')); assert(all(size(a) == [1 Inf])); end x = sum(a); 

并可以像这样调用:

 a = [ 1 2; 3 4] r = test(a) 

生产:

 r = 4 6 

不幸的是,生成的C无法实现Matlab可以实现的目标(即返回一个数组):

 __declspec(dllexport) real_T test(const emxArray_real_T *a); real_T test(const emxArray_real_T *a) { real_T x; int32_T k; if (a->size[1] == 0) { x = 0.0; } else { x = a->data[0]; for (k = 2; k size[1]; k++) { x += a->data[k - 1]; } } return x; } 

我假设MATLAB数组结构使用col-major排序。 在这种情况下,struct构造函数需要如下所示:

 public EmxArrayRealTWrapper(double[,] data) { int nRow = data.GetLength(0); int nCol = data.GetLength(1); double[] flattenedData = new double[nCol * nRow]; int index = 0; for (int col=0; col 

如果本机代码需要row-major,那么它就更简单了。 AC#多维数组存储为连续的行主arrays。 因此,您可以使用与我最近提出的问题中提供的一维代码非常相似的代码。

 public EmxArrayRealTWrapper(double[,] data) { int nRow = data.GetLength(0); int nCol = data.GetLength(1); _dataHandle = GCHandle.Alloc(data, GCHandleType.Pinned); _value.data = _dataHandle.AddrOfPinnedObject(); _sizeHandle = GCHandle.Alloc(new int[] { nRow, nCol }, GCHandleType.Pinned); _value.size = _sizeHandle.AddrOfPinnedObject(); _value.allocatedSize = nCol * nRow; _value.numDimensions = 2; _value.canFreeData = false; } 

请注意,这两种变体在将数据传递给本机代码的方式上有所不同。 第一个版本传递原始数据的副本。 第二个传递对原始数据的引用。 我不确定您希望代码如何表现。 很容易调整第二个版本来传递副本。 对于第一个版本,如果您希望本机代码修改数据并将这些修改反映回托管代码,那么您需要在返回本机调用后重新编组修改。