使包装器类适用于二维情况 [英] adapt wrapper class for two dimensional case

查看:106
本文介绍了使包装器类适用于二维情况的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

此问题是此问题的扩展.

我想使包装器适合二维情况.这是我的第一次尝试:

I would like to adapt the wrapper for the two dimensional case. This is my first attempt:

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代码如下:

The orginal matlab code looks like this:

    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可以实现的目标(即返回数组):

Unfortunately the produced C cannot achieve what Matlab can achieve (i.e. return an array):

__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 <= a->size[1]; k++) {
      x += a->data[k - 1];
    }
  }

  return x;
}

推荐答案

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

I'm assuming that the MATLAB array struct use col-major ordering. In which case the struct constructor needs to look like this:

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<nCol; col++)
    {
        for (int row=0; row<nRow; row++)
        {
            flattenedData[index] = data[row, col];
            index++;
        }
    }                    

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

如果本机代码期望行优先,那么它会更简单. C#多维数组存储为连续的行为主数组.因此,您可以使用与我在最近的问题中提供的一维代码非常相似的代码.

If the native code expects row-major then it's simpler. A C# multi-dimensional array is stored as a contiguous row-major array. So you can use code very similar to the one dimensional code I provided in your recent question.

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;
}

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

Note well that these two variants differ in the way they pass the data to the native code. The first version passes a copy of the original data. The second passes a reference to the original data. I'm not sure how you want your code to behave. It's easy enough to adapt the second version to pass a copy. As for the first version, if you wanted the native code to modify the data and have those modifications reflected back to the managed code, then you'd need to marshal the modifications back after the native call returned.

这篇关于使包装器类适用于二维情况的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆