代码之家  ›  专栏  ›  技术社区  ›  Residuum

带有P/Invoke和指针的泛型

  •  4
  • Residuum  · 技术社区  · 8 年前

    我使用的是具有回调函数的C接口,其中软件正在处理指针。

    在C#端,我有以下代码用于将指针复制到托管数组并返回,例如 float * .

    class FloatPointer
    {
        readonly unsafe float* _pointer;
    
        public uint Size { get; set; }
    
        public float[] Array { get; set; }
    
        public unsafe void CopyToPointer ()
        {
            int length = (int)Math.Min (Size, Array.Length);
            Marshal.Copy (Array, 0, (IntPtr)_pointer, length);
            for (int i = length; i < Size; i++) {
                _pointer [i] = 0;
            }
        }
    
        unsafe float[] CopyFromPointer ()
        {
            float[] result = new float[Size];
            Marshal.Copy ((IntPtr)_pointer, result, 0, (int)Size);
            return result;
        }
    
        public unsafe FloatPointer (float* pointer, uint size)
        {
            _pointer = pointer;
            Size = size;
            Array = CopyFromPointer ();
        }
    }
    

    因为我也必须这样做 unsigned char* , uint* 我在考虑使用一个泛型类, class Pointer<T>: where T: ValueType .

    不幸的是,这种限制是不可能的。

    如果我将其更改为无约束的泛型类,那么 Marshal.Copy 告诉我它不知道 T[] .

    有什么方法可以创建这个泛型类吗?

    1 回复  |  直到 8 年前
        1
  •  2
  •   jjxtra    8 年前

    我相信这门课会做你想做的。它具有从数组转换为指针和返回的方法,并且是泛型类型参数。

    public class StructPointer<T> where T : struct
    {
        /// <summary>
        /// Pointer
        /// </summary>
        public IntPtr Pointer { get; set; }
    
        /// <summary>
        /// Number of elements in pointer
        /// </summary>
        public int PointerElementCount { get; set; }
    
        /// <summary>
        /// Array
        /// </summary>
        public T[] Array { get; set; }
    
        private int sizeOfT;
    
        /// <summary>
        /// Copy Array to Pointer
        /// </summary>
        public void ArrayToPointer()
        {
            if (Array == null || Pointer == IntPtr.Zero)
            {
                return;
            }
    
            int length = (int)Math.Min(PointerElementCount, Array.Length);
            int byteCount = length * sizeOfT;
            GCHandle handle = GCHandle.Alloc(Array, GCHandleType.Pinned);
            unsafe
            {
                for (int i = 0; i < byteCount; i++)
                {
                    *(((byte*)Pointer) + i) = *(((byte*)handle.AddrOfPinnedObject()) + i);
                }
            }
            handle.Free();
    
            if (PointerElementCount > Array.Length)
            {
                unsafe
                {
                    int byteCount2 = byteCount + (sizeOfT * (PointerElementCount - Array.Length));
                    for (int i = byteCount; i < byteCount2; i++)
                    {
                        *(((byte*)Pointer) + i) = 0;
                    }
                }
            }
        }
    
        /// <summary>
        /// Copy Pointer to Array
        /// </summary>
        public void ArrayFromPointer()
        {
            if (Pointer == IntPtr.Zero)
            {
                return;
            }
    
            Array = new T[PointerElementCount];
            GCHandle handle = GCHandle.Alloc(Array, GCHandleType.Pinned);
            int byteCount = Array.Length * sizeOfT;
            unsafe
            {
                for (int i = 0; i < byteCount; i++)
                {
                    *(((byte*)handle.AddrOfPinnedObject()) + i) = *(((byte*)Pointer) + i);
                }
            }
            handle.Free();
        }
    
        public StructPointer()
        {
            sizeOfT = Marshal.SizeOf(typeof(T));
        }
    
        /// <summary>
        /// Constructor. Copies pointer to Array.
        /// </summary>
        /// <param name="pointer">Pointer</param>
        /// <param name="length">Number of elements in pointer</param>
        public StructPointer(IntPtr pointer, int length)
        {
            sizeOfT = Marshal.SizeOf(typeof(T));
            Pointer = pointer;
            PointerElementCount = length; // number of elements in pointer, not number of bytes
            ArrayFromPointer();
        }
    }