如何在保存本机内存的类上实现AsSpan()?

时间:2018-07-06 15:43:55

标签: c# .net

我的类型可以保存一些本机内存。我想在其上实现AsSpan(),以便可以安全地访问本机内存。

下面是一个幼稚的尝试,显示了我正在尝试做的事情。显然Span<T>不会使Holder对象保持活动状态,因为它仅具有指向本机内存的指针,而没有对Holder对象的引用。我也尝试实现MemoryManager<T>,但是我也看不出如何使Span<T>使管理器对象保持活动状态。

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;

internal class Program
{
    public static void Main()
    {
        Span<byte> span = GetSpan();
        GC.Collect();
        GC.WaitForPendingFinalizers();
        span[span.Length - 1] = 0;  // Access violation
    }

    private static Span<byte> GetSpan()
    {
        Span<byte> span = new Holder(1 << 20).AsSpan();
        GC.Collect();
        GC.WaitForPendingFinalizers();
        span[span.Length - 1] = 0;  // OK
        return span;
    }
}

public class Holder
{
    private readonly int _size;
    private readonly IntPtr _pointer;

    public Holder(int size)
    {
        _size = size;
        _pointer = Marshal.AllocHGlobal(_size);
    }

    ~Holder()
    {
        Marshal.FreeHGlobal(_pointer);
        Debug.WriteLine("{0:X} was freed", _pointer);
    }

    public Span<byte> AsSpan()
    {
        unsafe { return new Span<byte>((void*)_pointer, _size); }
    }
}

Span<T>能够使诸如Stringbyte[]之类的托管对象保持活动状态。有没有一种方法可以对本机内存持有人类型实现AsSpan(),以便Span<T>使持有人对象保持活动状态?

1 个答案:

答案 0 :(得分:1)

对于每个this discussion,无法使用Span<T>来控制非托管内存的生存期。

您可以实现MemoryManager<T>来管理非托管内存的生存期,在using块中使用它,并且只要Span<T>不逃避using块,它会很安全的。 (但是不可能强迫API使用者安全使用API​​。)