【发布时间】:2020-08-06 06:08:25
【问题描述】:
我正在使用SequenceReader<T> 将内容从ReadOnlySequence<T> 复制到不同的Span<T>。但是,当我尝试将复制逻辑封装到单独的函数中并希望使用堆栈上分配的 Span<T> 来调用它时,出现编译器错误。
var sequence = new ReadOnlySequence<byte>(new byte[20]); // Source data to copy
Span<byte> heap = new byte[10]; // Target location 1
Span<byte> stack = stackalloc byte[10]; // Target location 2
var reader = new SequenceReader<byte>(sequence);
TryReadInto(ref reader, heap); // This is fine
TryReadInto(ref reader, stack); // Gives compile time error CS8350
由于SequenceReader<T> 上的实例方法TryCopyTo 没有让读者受益,我创建了一个更高级别的函数来处理这个问题:
[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;
}
只要目标是堆分配的,一切正常。但是,当使用stackalloc 分配目标时,编译器会报错CS8350:不允许使用这种参数组合,因为它可能会将参数引用的变量暴露在其声明范围之外。
当我不将阅读器作为参考传递时,编译器错误就会消失,但自SequenceReader<T> is a mutable struct 以来需要将阅读器作为参考传递,并且该位置在函数内是高级的。
我得到编译器错误。参数reader 可以在较早的堆栈帧中分配,并且作为类似ref 的结构将能够将Span<T> 作为字段。方法体可以使第二个(堆栈分配的)参数 destination 转义它自己的堆栈帧,因此在 C# 中同时使用 ref 参数和堆栈分配的 Span<T> 的函数调用是非法的。
但是,我该如何封装我的逻辑呢? SequenceReader<T> 是一个封闭类型,所以我不能只添加一个实例方法。当我手动内联函数调用时,我没有收到编译器错误。我猜编译器看到读取器被分配在与堆栈分配的Span<byte> 相同的堆栈帧中。因为SequenceReader<T>is a mutable struct,所以不能通过值传递读者。
【问题讨论】: