C#使用内存访问非托管阵列<;T>;或排列排列<;T>;?

C#使用内存访问非托管阵列<;T>;或排列排列<;T>;?,c#,unmanaged-memory,C#,Unmanaged Memory,随着C#7.2中内存、Span和ArraySegment的引入,我想知道是否可以将非托管数组表示为位于堆上的可枚举对象 后一个要求排除了Span,后者基本上实现了我想要的:例如 unsafe { bytes = new Span<byte>((byte*)ptr + (index * Width), Width); unsafe{bytes=newspan((字节*)ptr+(索引*宽度),宽度); 有没有可能对ArraySegment或Memory执行相同的操作?它们的构造函

随着C#7.2中
内存
Span
ArraySegment
的引入,我想知道是否可以将非托管数组表示为位于堆上的可枚举对象

后一个要求排除了
Span
,后者基本上实现了我想要的:例如

unsafe { bytes = new Span<byte>((byte*)ptr + (index * Width), Width); 
unsafe{bytes=newspan((字节*)ptr+(索引*宽度),宽度);
有没有可能对
ArraySegment
Memory
执行相同的操作?它们的构造函数只接受
byte[]
,也许有某种方法可以欺骗C#传递
byte*
而不是
byte[]

对于
内存
来说是的,但是您需要创建自己的
内存管理器
。别担心-这并不像听起来那么可怕-:

//
///原始指针上的内存管理器
/// 
///假定指针为完全非托管或外部固定-不会尝试固定此数据
公共密封的不安全类UnmanagedMemoryManager:MemoryManager
其中T:非托管
{
专用只读T*_指针;
私有只读整数长度;
/// 
///以给定的指针和大小创建新的UnmanagedMemoryManager实例
/// 
///假定提供的跨距已处于非托管或外部固定状态
公共非托管内存管理器(Span)
{
固定(T*ptr=&MemoryMarshal.GetReference(span))
{
_指针=ptr;
_长度=跨度长度;
}
}
/// 
///以给定的指针和大小创建新的UnmanagedMemoryManager实例
/// 
公共非托管内存管理器(T*指针,整数长度)
{
如果(长度<0)抛出新ArgumentOutOfRangeException(nameof(长度));
_指针=指针;
_长度=长度;
}
/// 
///获取表示区域的范围
/// 
公共覆盖Span GetSpan()=>新Span(\u指针,\u长度);
/// 
///提供对表示数据的指针的访问(注意:没有实际的pin)
/// 
公共重写内存句柄Pin(int elementIndex=0)
{
如果(元素索引<0 | |元素索引>=\u长度)
抛出新ArgumentOutOfRangeException(nameof(elementIndex));
返回新的MemoryHandle(_指针+元素索引);
}
/// 
///无效
/// 
公共重写void Unpin(){}
/// 
///释放与此对象关联的所有资源
/// 
受保护的重写void Dispose(bool disposing){}
}
现在您可以使用:

var mgr = new UnmanagedMemoryManager((byte*)ptr + (index * Width), Width);
Memory<byte> memory = mgr.Memory;
var-mgr=newunmanagedmemorymanager((字节*)ptr+(索引*宽度),宽度);
内存=管理内存;
内存
可以存储在堆上


但是,要最小化分配,您可能需要创建一个覆盖整个区域的
非托管内存管理器
,仅一次,然后在
内存
上使用表示整个区域的
.Slice(…)
。这样,您就有了一个对象和许多切片(切片是结构,而不是对象)


注意:这个实现假设您将在其他地方控制内存的生存期,
Dispose()
此处不会尝试通过
封送
等方式释放内存。

为什么要使用
Span
内存
执行此操作?您可以
封送.GlobalHAlloc
并获得一个
IntPtr
来直接使用一组非托管内存。您可以以某种方式将其转换为
byte[]
可以传递到这些对象中。您是想创建一个新的内存块来处理,还是想访问另一个进程内存块?我正在使用SkiaSharep加载图像,并逐字节进行迭代。目前,我使用提供的属性将数据复制为
byte[]
可以使用,但Skia还提供了指向非托管内存的本机指针,我想探索它,因为它为我保存了一个内存副本。@RonBeyer
内存
实际上非常适合于此…@MarcGravel我同意现在我理解了用例,但我不知道自定义
内存管理器
,谢谢!
UnmanagedMemoryManager
-如果我见过悖论的话,这是对悖论的合理使用。@AaronLS我觉得这似乎有点矛盾agree@AaronLS也许它需要一个经理,因为它“不受管理”?;-)@MarcGravel这太神奇了。我需要做什么特殊的事情来使用它吗?我得到
找不到类型或命名空间名称“unmanaged”
。已经导入
系统。缓冲区
互操作服务
我删除了
unmanaged
接口和所有泛型,它现在正在工作。
var mgr = new UnmanagedMemoryManager((byte*)ptr + (index * Width), Width);
Memory<byte> memory = mgr.Memory;