困惑从IntPtr的访问元素在C#

问题描述:

我使用的Kinect V2包含以下CameraSpacePoint结构:困惑从IntPtr的访问元素在C#

public struct CameraSpacePoint : IEquatable<CameraSpacePoint> 
{ 
    public float X; 
    public float Y; 
    public float Z; 
} 

CameraSpacePoint还包含一些方法EqualsGetHashCode等,上面没有显示保留职位干净而短暂。

好,我在类构造定义cameraSpacePoints如下:

IntPtr cameraSpacePoints = Marshal.AllocHGlobal(512 * 424 * 4 * 3); 

下面是上述存储器分配的说明:

  • 512:宽度
  • 424:高度
  • 4 :单个“浮点数”所需的字节数
  • 3:总共三个变量,即'X','Y

    coordinateMapper.MapDepthFrameToCameraSpaceUsingIntPtr(depthFrameData, 
                    512 * 424 * 2, 
                    cameraSpacePoints, 
                    512 * 424 * 4 * 3); 
    

    似乎完美的:'和 'Z'

后来,我用CoordinateMapper如下复制值cameraSpacePoints。现在我想从cameraSpacePoints获取值。所以我用下面的代码里面unsafe块:

float* cameraSpacePoint = (float*)cameraSpacePoints; 
for (var index = 0; index < 512 * 424; index++) 
{ 
    float X = cameraSpacePoint[index]; 
    float Y = cameraSpacePoint[index + 1]; 
    float Z = cameraSpacePoint[index + 2]; 
} 

它似乎没有我,而它的可视化实现的工作。在我看来,使用IntPtr从cameraSaPointPoints访问元素时存在一些混淆。这里缺少什么?有什么建议吗?

+1

尝试在for循环中用'index + = 3'替换'index ++' - 看起来你一次只做3个浮动。此外,作为转换为单个float *的替代方法,您可以转换为'CameraSpacePoint',它将封装X,Y和Z. – StuartLC

+0

@StuartLC:情况变得更好,现在*我看到相同数据的三个副本* 。换句话说,我在同一个窗口看到自己三次! LOL –

+0

@StuartLC:令人惊讶的是,铸造技巧奏效。 'CameraSpacePoint * cameraSpacePoint =(CameraSpacePoint *)cameraSpacePoints;''然后'X = cameraSpacePoint [index] .X,'你能回答并解释为什么'float *'不起作用,但''CameraSpacePoint *'起作用吗?非常感谢你。 –

在您的初始代码中,您正在将IntPtr(指向CameraSpacePoint的数组[]]指向原始浮点型指针。如果您将IntPtr解释为原始的float s,由于您一次处理3个点(x,y和z),因此您需要每次将循环增加3个浮点数。 (我已经改名为清楚起见变量):

var floats = (float*)cameraSpacePoints; 
for (var index = 0; index < 512 * 424; index+=3) 
{ 
    var x = floats[index]; 
    var y = floats[index + 1]; 
    var z = floats[index + 2]; 
    var myCameraSpacePoint = new CameraSpacePoint 
    { 
     X = x, 
     Y = y, 
     Z = z 
    }; 
    // use myCameraSpacePoint here 
} 

但是,这是处理数据一个可怕的低效的方式,因为该数据最初在任何情况下一个CameraSpacePoint。更好的将只是施放的结构直接返回到实际类型:

var cameraSpacePoints = (CameraSpacePoint*)cameraSpacePoints; 
for (var index = 0; index < 512 * 424; index++) 
{ 
    var cameraSpacePoint = cameraSpacePoints[index]; 
    // Do something with cameraSpacePoint 
} 

通过转换成正确的类型(CameraSpacePoint),我们也提高了代码的健壮性 - 例如如果未来将更多字段添加到CameraSpacePoint的新版本中,那么针对新版本的代码重新编译将再次运行,而直接访问float会破坏封装并使维护变得困难。

我们之所以不再需要将循环增加3,是因为当我们在cameraSpacePoints[index]上使用下标/索引操作时,编译器是否知道在位置为n * sizeof(CameraSpacePoint)之后发现元素n初始的cameraSpacePoints[0]。并且sizeof(CameraSpacePoint)是3个浮标的大小。

+1

非常感谢。 –