代码之家  ›  专栏  ›  技术社区  ›  Red Riding Hood

使用内存<T>或ArraySegment<T>访问非托管数组?

  •  6
  • Red Riding Hood  · 技术社区  · 6 年前

    随着 Memory , Span ArraySegment

    跨度 基本上实现了我想要的:例如。

    unsafe { bytes = new Span<byte>((byte*)ptr + (index * Width), Width); 
    

    有没有可能用同样的方法 排列分段 记忆 ? 他们的施工人员只接受 byte[] ,也许有什么办法可以骗C#通过a byte* 而不是 ?

    1 回复  |  直到 6 年前
        1
  •  20
  •   Marc Gravell    6 年前

    是的 Memory<T> ,但你需要创建自己的 MemoryManager<T> . 别担心-这并不像听起来那么可怕- here's one I wrote earlier... :

    /// <summary>
    /// A MemoryManager over a raw pointer
    /// </summary>
    /// <remarks>The pointer is assumed to be fully unmanaged, or externally pinned - no attempt will be made to pin this data</remarks>
    public sealed unsafe class UnmanagedMemoryManager<T> : MemoryManager<T>
        where T : unmanaged
    {
        private readonly T* _pointer;
        private readonly int _length;
    
        /// <summary>
        /// Create a new UnmanagedMemoryManager instance at the given pointer and size
        /// </summary>
        /// <remarks>It is assumed that the span provided is already unmanaged or externally pinned</remarks>
        public UnmanagedMemoryManager(Span<T> span)
        {
            fixed (T* ptr = &MemoryMarshal.GetReference(span))
            {
                _pointer = ptr;
                _length = span.Length;
            }
        }
        /// <summary>
        /// Create a new UnmanagedMemoryManager instance at the given pointer and size
        /// </summary>
        public UnmanagedMemoryManager(T* pointer, int length)
        {
            if (length < 0) throw new ArgumentOutOfRangeException(nameof(length));
            _pointer = pointer;
            _length = length;
        }
        /// <summary>
        /// Obtains a span that represents the region
        /// </summary>
        public override Span<T> GetSpan() => new Span<T>(_pointer, _length);
    
        /// <summary>
        /// Provides access to a pointer that represents the data (note: no actual pin occurs)
        /// </summary>
        public override MemoryHandle Pin(int elementIndex = 0)
        {
            if (elementIndex < 0 || elementIndex >= _length)
                throw new ArgumentOutOfRangeException(nameof(elementIndex));
            return new MemoryHandle(_pointer + elementIndex);
        }
        /// <summary>
        /// Has no effect
        /// </summary>
        public override void Unpin() { }
    
        /// <summary>
        /// Releases all resources associated with this object
        /// </summary>
        protected override void Dispose(bool disposing) { }
    }
    

    var mgr = new UnmanagedMemoryManager((byte*)ptr + (index * Width), Width);
    Memory<byte> memory = mgr.Memory;
    

    memory 可以存储在堆上。

    UnmanagedMemoryManager<byte> 涵盖了 整个的 区域-仅限一次-然后使用 .Slice(...) .Memory

    注意:这个实现假设您将在其他地方控制内存的生存期—内存 Dispose() 在这里 没有 Marshal 等。

    推荐文章