我被困在一个看似简单的工作上,需要你的帮助.
我需要编写一个具有以下签名的方法:
System.Array ToIntPtrArray(System.Array a)
其中实际的参数可以是任何pointer type的数组(例如int * [],long ** [],void * [,]),并返回与类型为System.IntPtr
的元素具有相同数值的元素相同形状的数组的输入数组.问题是如果我不知道他们的类型,我不明白如何提取指针的数值.
例如,如果我事先知道我的参数总是类型为void * [],我可以写如下的方法:
unsafe IntPtr[] ToIntPtrArray(void*[] a) { var result = new IntPtr[a.Length]; for (int i = 0; i < a.Length; i++) result[i] = (IntPtr) a[i]; return result; }
但问题是它可能不是void * [],但是void ** []或其他任何东西,并且该方法应该能够处理所有的情况.
解决方法
简单的答案是,这不能直接做到.原因是,如果您传递转换函数,则任何执行索引操作的常规索引功能容器(System.Array,Collections.IList,ArrayList等)都将尝试将结果转换为System.Object. C#中的指针不派生自Object,所以这将导致SystemNotSupported或类似异常.
有两个合理的解决方法:
>在调用之前将指针数组转换为void指针数组
方法.
>将指针数组转换为void指针指针
调用方法.
第一个是相当麻烦的,因为它需要使用for循环复制数组的整个内容.第二个选项需要传递数组的长度,因为它不再被托管的System.Array对象包装.
示例代码
方法:
unsafe Array ToIntPtrArray(void** a,int count) { IntPtr[] intPtrArray = new IntPtr[count]; for (int n = 0; n < count; n++) intPtrArray[n] = new IntPtr(a[n]); return intPtrArray; }
示例用法(整数指针数组):
int*[] intPtrArray; // Code that initializes the values of intPtrArray fixed(int** ptr = &intPtrArray[0]) { Array result = ToIntPtrArray((void**)ptr,intPtrArray.Length); }
示例用法(void pointer pointer array):
void**[] voidPtrPtrArray; // Code that initializes the values of voidPtrPtrArray fixed(void*** ptr = &voidPtrPtrArray[0]) { Array result = ToIntPtrArray((void**)ptr,voidPtrPtrArray.Length); }
示例用法(多维int指针数组):
int*[,] int2dArray; // Code that initializes the values of int2dArray fixed(int** ptr = &int2dArray[0,0]) { Array result = ToIntPtrArray((void**)ptr,TotalSize(int2dArray)); Array reshaped = ReshapeArray(result,int2dArray); }
其中TotalSize和ReshapeArray是用于处理多维数组的辅助函数.有关如何完成此操作的提示,请参阅:Programatically Declare Array of Arbitrary Rank.