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