C# 通过stackalloc和x27;埃德·斯潘<;T>;并以ref struct作为参数

C# 通过stackalloc和x27;埃德·斯潘<;T>;并以ref struct作为参数,c#,.net-core,clr,C#,.net Core,Clr,我正在使用SequenceReader将内容从ReadOnlySequence复制到不同的Span中。但是,当我试图将复制逻辑封装到一个单独的函数中,并希望使用堆栈上分配的Span调用它时,会出现一个编译器错误 var序列=新的只读序列(新字节[20]);//要复制的源数据 Span heap=新字节[10];//目标位置1 Span stack=stackalloc字节[10];//目标位置2 变量读取器=新序列读取器(序列); TryReadInto(参考读取器,堆);//这很好 TryRe

我正在使用
SequenceReader
将内容从
ReadOnlySequence
复制到不同的
Span
中。但是,当我试图将复制逻辑封装到一个单独的函数中,并希望使用堆栈上分配的
Span
调用它时,会出现一个编译器错误

var序列=新的只读序列(新字节[20]);//要复制的源数据
Span heap=新字节[10];//目标位置1
Span stack=stackalloc字节[10];//目标位置2
变量读取器=新序列读取器(序列);
TryReadInto(参考读取器,堆);//这很好
TryReadInto(参考读取器,堆栈);//给出编译时错误CS8350
由于
SequenceReader
上的实例方法不能提高读取器的速度,因此我创建了一个更高级别的函数来处理这个问题:

[MethodImpl(MethodImplOptions.AggressiveInlining)]
static bool TryReadInto(ref SequenceReader<byte> reader, Span<byte> destination)
{
    if (reader.TryCopyTo(destination)) {
        reader.Advance(destination.Length);
        return true;
    }

    return false;
}
[MethodImpl(MethodImplOptions.AggressiveInline)]
静态bool TryReadInto(参考SequenceReader读取器,范围目标)
{
if(读卡器TryCopyTo(目的地)){
读卡器。前进(目的地。长度);
返回true;
}
返回false;
}
只要目标是堆分配的,一切正常。但是当使用
stackalloc
分配目标时,编译器会向CS8350抱怨:不允许将参数组合到,因为它可能会将参数引用的变量暴露在其声明范围之外

当我没有将读卡器作为引用传递时,编译器错误会消失,但是需要将读卡器作为引用传递,因为
SequenceReader
,并且该位置在函数中是高级的

我得到了编译器错误。参数
reader
可以在较早的堆栈帧中分配,并且作为类ref结构,可以将
Span
作为字段。方法主体可以使第二个(堆栈分配的)参数
destination
转义它自己的堆栈帧,因此在C#中,同时使用
ref
-参数和堆栈分配
Span
的函数调用是非法的


但是,我怎样才能封装我的逻辑呢?
SequenceReader
是一种封闭类型,所以我不能只添加实例方法。当我只是手动内联函数调用时,不会出现编译器错误。我猜编译器看到读卡器被分配到与分配的堆栈相同的堆栈帧中
Span
。通过值传递读取器不是一个选项,因为您已经看到编译器试图防止的问题

如果我将您在问题中描述的内容转换为C#,代码可能如下所示:

// This is a struct lives on stack
ref struct SomeStructOnStack
{
    public Span<byte> Something;
}

// This method saves "stack" to the "obj"
static void SomeMethod(ref SomeStructOnStack obj, Span<byte> stack)
{
    obj = new SomeStructOnStack
    {
        Something = stack
    };
}

// This method accepts byref "obj" from its caller
// In such case, "stack" will escape its scope
// This is what CS8350 is for
void Test(ref SomeStructOnStack obj)
{
    Span<byte> stack = stackalloc byte[20];
    SomeMethod(ref obj, stack);
}
Span<byte> stack = stackalloc byte[20];

unsafe
{
    fixed (byte* pStack = stack)
    {
        var copy = new Span<byte>(pStack, stack.Length);
        TryReadInto(ref reader, copy);
    }
}

有趣的是,通过返回到不安全的指针逻辑,我们可以告诉编译器我们知道我们在做什么,它不应该抱怨,而只是编译代码。我有一种感觉,这是安全代码的一个限制,所以我已经开始提交了。