我怎样才能投内存 另一

问题描述 投票:5回答:2

我们可以通过Span<T>方法重载投ReadOnlySpan<T>MemoryMarshal.Cast到另一个。喜欢 :

Span<byte> span = stackalloc byte[4];
var singleIntSpan = MemoryMarshal.Cast<byte, int>(span);

但是,有没有办法投Memory<T>到另一个?例如投Memory<byte>Memory<ushort>

c#
2个回答
6
投票

你不能直接这样做;然而,如果你真的需要,你可以创建自定义MemoryManager<T>(大概是实际执行中投作为MyMemoryManager<TFrom, TTo> : MemoryManager<TTo>覆盖的部分GetSpan()这是稍微不平凡的,并要求另一分配 - 不像Span<T>投,这是allocation-自由。

如果你需要的是一个具体的例子,我能击败一起来(其实我做的正是这样一些现有的代码),而是:说实话,你可能要重新考虑的方案来代替。

编辑:是这样的:

using System;
using System.Buffers;
using System.Runtime.InteropServices;

class Program
{
    static void Main()
    {
        Memory<byte> bytes = new byte[1024];

        Memory<ushort> typed = Utils.Cast<byte, ushort>(bytes);
        Console.WriteLine(typed.Length); // 512

        // note CPU endianness matters re the layout
        typed.Span[0] = 0x5432;
        Console.WriteLine(bytes.Span[0]); // 50 = 0x32
        Console.WriteLine(bytes.Span[1]); // 84 = 0x54
    }
}

static class Utils
{
    public static Memory<TTo> Cast<TFrom, TTo>(Memory<TFrom> from)
        where TFrom : unmanaged
        where TTo : unmanaged
    {
        // avoid the extra allocation/indirection, at the cost of a gen-0 box
        if (typeof(TFrom) == typeof(TTo)) return (Memory<TTo>)(object)from;

        return new CastMemoryManager<TFrom, TTo>(from).Memory;
    }
    private sealed class CastMemoryManager<TFrom, TTo> : MemoryManager<TTo>
        where TFrom : unmanaged
        where TTo : unmanaged
    {
        private readonly Memory<TFrom> _from;

        public CastMemoryManager(Memory<TFrom> from) => _from = from;

        public override Span<TTo> GetSpan()
            => MemoryMarshal.Cast<TFrom, TTo>(_from.Span);

        protected override void Dispose(bool disposing) { }
        public override MemoryHandle Pin(int elementIndex = 0)
            => throw new NotSupportedException();
        public override void Unpin()
            => throw new NotSupportedException();
    }
}

如果你真的想支持锁定/解锁,这应该是可能的 - 你只需要计算的相对范围和偏移,从竞争TFrom / TTo,虽然 - 大概使用Unsafe.SizeOf<T>等,并使用MemoryMarshal.TryGetMemoryManager让底层的内存管理器(如果有的话 - 请注意,裸数组没有内存管理器)。除非你要广泛测试选项,投掷可能比犯错更安全。


2
投票

我不认为你可以,不过,我想你可以从它返回一个跨度,但我怀疑它会帮助

Memory.Span Property

返回从当前实例的跨度。

var array = new int[4];
var mem = array.AsMemory();
var span = MemoryMarshal.Cast<int, byte>(mem.Span);
© www.soinside.com 2019 - 2024. All rights reserved.