C# 7.2 引入了 Span<T>
,以类型安全和内存安全的方式表示任意内存的连续部分。
- Q: 作为一个特殊的
ref struct
,当Span<T>
在方法间传递(包括以参数或返回值传递)时,传递的是引用还是一个深拷贝? - A:
Span<T>
在方法间传递时是传递引用,而不是深拷贝。
- Q: 当执行
Span<T>.Slice
来切片时,创建的是深拷贝还是浅拷贝?换言之,对调用后创建的切片Span<T>
操作是否会影响原有的Span<T>
实例? - A:
Span<T>.Slice
方法创建的是浅拷贝,即调用后创建的切片Span<T>
操作会影响原有的Span<T>
实例。
- Q:
ReadOnlySpan<T>
表示任意连续内存区域的类型安全和内存安全只读表示形式。如何从一个ReadOnlySpan<T>
创建可写的Span<T>
? - A: 可以使用
MemoryMarshal.CreateSpan(ref T, int)
或者MemoryMarshal.CreateWritableSpan(ref T, int)
方法从一个ReadOnlySpan<T>
创建可写的Span<T>
。
- Q:
Span<T>
作为 ref 结构类型有诸多限制,以确保它们不能提升到托管堆,包括不能装箱、不能分配给 Object 类型的 dynamic 变量或任何接口类型,它们不能是引用类型中的字段,也不能跨 await 和 yield 边界使用。它是否能作为委托类型(如Func<>
,Action<>
)的参数传递? - A:
Span<T>
不能作为委托类型的参数传递,因为它既不是类类型也不是接口类型。如果需要在委托中使用Span<T>
,需要使用一个类来包装它。
(可能的错误:Span<T>
不能是引用类型中的字段。)
-
Q:
ReadOnlySpan<T>
表示任意连续内存区域的类型安全和内存安全只读表示形式。如何从一个Span<T>
创建一个只读的ReadOnlySpan<T>
切片? -
A: 可以通过调用
AsReadOnly()
方法将Span<T>
转换为ReadOnlySpan<T>
。以下是示例代码:Span<int> span = new int[] { 1, 2, 3, 4, 5 }; ReadOnlySpan<int> readOnlySpan = span.AsReadOnly();
在上面的代码中,我们首先创建了一个
Span<int>
,然后通过调用AsReadOnly()
方法将其转换为只读ReadOnlySpan<int>
。由于ReadOnlySpan<T>
是只读的,因此转换后的readOnlySpan
不允许修改。注意,
AsReadOnly()
方法返回的是只读的ReadOnlySpan<T>
的一个实例,因此它不会改变原始Span<T>
实例。