是否可以将新的 System.Memory Span 结构与二维数据数组一起使用?
double[,] testMulti =
{
{ 1, 2, 3, 4 },
{ 5, 6, 7, 8 },
{ 9, 9.5f, 10, 11 },
{ 12, 13, 14.3f, 15 }
};
double[] testArray = { 1, 2, 3, 4 };
string testString = "Hellow world";
testMulti.AsSpan(); // Compile error
testArray.AsSpan();
testString.AsSpan();
虽然 testArray 和 testString 有 AsSpan 扩展,但 testMulti 不存在这样的扩展。
Span 的设计仅限于处理一维数据数组吗?
我还没有找到使用 Span 处理 testMulti 数组的明显方法。
您可以创建一个具有非托管内存的
Span
。这将允许您不加区别地“切片和切块”。
unsafe
{
Span<T> something = new Span<T>(pointerToarray, someLength);
}
完整演示
unsafe public static void Main(string[] args)
{
double[,] doubles = {
{ 1, 2, 3, 4 },
{ 5, 6, 7, 8 },
{ 9, 9.5f, 10, 11 },
{ 12, 13, 14.3f, 15 }
};
var length = doubles.GetLength(0) * doubles.GetLength(1);
fixed (double* p = doubles)
{
var span = new Span<double>(p, length);
var slice = span.Slice(6, 5);
foreach (var item in slice)
Console.WriteLine(item);
}
}
7
8
9
9.5
10
其他选项是重新分配到单维数组,承担惩罚并且不要Pass-Go
BlockCopy
memcpy
unsafe
和指针Cast<T>
multiDimensionalArrayData.Cast<byte>().ToArray()
MemoryMarshal.CreateSpan
和
MemoryMarshal.GetArrayDataReference
。public static Span<T> AsSpan<T>(this Array array)
{
return MemoryMarshal.CreateSpan(ref Unsafe.As<byte, T>(ref MemoryMarshal.GetArrayDataReference(array)), array.Length);
}
点网小提琴 这适用于数组的所有维度。如果您希望泛型类型推断起作用,则需要为每个等级(维度级别)使用单独的函数,例如
AsSpan<T>(this T[,] array)
和
AsSpan<T>(this T[,,] array)
。public static Span<T> AsSpan<T>(this T[,] array) => ((Array)array).AsSpan();
public static Span<T> AsSpan<T>(this T[,,] array) => ((Array)array).AsSpan();
public static Span<T> AsSpan<T>(this T[,,,] array) => ((Array)array).AsSpan();
// etc
查看文档
这里。
您可以在此处
找到寻址 nuget 包。
该软件包还提供了 Memory2D。
var arr = new int[,] { {1,2,3},{2,2,3},{3,2,3} };
var spn = arr.AsSapn2D();
// Now use it similar to a normal span
// The access is of course a bit different since we are using a 2D data structure.
Console.WriteLine(spn[0..2,..]);
您当然可以将各种结构映射到一维内存上,但 Span 类不会为您做这件事。但你可以轻松地自己写一些东西,例如:
public class Span2D<T> where T : struct
{
protected readonly Span<T> _span;
protected readonly int _width;
protected readonly int _height;
public Span2D(int height, int width)
{
T[] array = new T[_height * _width];
_span = array.AsSpan();
}
public T this[int row, int column]
{
get
{
return _span[row * _height + column];
}
set
{
_span[row * _height + column] = value;
}
}
}
棘手的部分是实现
Slice()
,因为对于二维结构来说语义有点模糊。您可能只能按其中一个维度对这种结构进行切片,因为按另一个维度对它进行切片会导致内存不连续。
您需要首先使用
将二维数组转换为列表(一维)的快速方法或转换二维数组中所示的技术来获取一个新的单维数组。
double[][] testMulti =
{
new double[] { 1, 2, 3, 4 },
new double[] { 5, 6, 7, 8 },
new double[] { 9, 9.5f, 10, 11 },
new double[] { 12, 13, 14.3f, 15 }
};
Span<double[]> span = testMulti.AsSpan(2, 1);
Span<double> slice = span[0].AsSpan(1, 2);
foreach (double d in slice)
Console.WriteLine(d);
slice[0] = 10.5f;
Console.Write(string.Join(", ", testMulti[2]));
Console.ReadLine();
9.5
10
9, 10.5, 10, 11