C#中Span2D的CopyTo方法无法正确复制二维范围求助
如何用Span2D实现二维数组的向下滚动(避免重叠复制覆盖问题)
你尝试用Span2D对二维数组执行向下滚动操作,期望将前两行向下复制一行,使数组从:
{ { 1, 1, 1, 1, 1 }, { 2, 2, 2, 2, 2 }, { 0, 0, 0, 0, 0 }, }
变为:
{ { 1, 1, 1, 1, 1 }, { 1, 1, 1, 1, 1 }, { 2, 2, 2, 2, 2 }, }
但直接使用Span2D.CopyTo复制前两行到后两行时,结果却变成了全第一行的数据,核心原因是重叠内存块的正向复制导致了数据覆盖。
问题根源
Span2D的CopyTo方法是按线性内存顺序复制的,而.NET中的二维数组采用行优先存储。以你的测试数组为例,内存布局是连续的:[1,2,3,4,5, 0,0,0,0,0, 0,0,0,0,0]
当你将前两行(前10个元素)复制到从第5个元素开始的后两行(第5到14个元素)时,复制顺序是从左到右:
- 先把前5个元素(第一行)复制到第5-9位(第二行),此时第二行的数据已被替换成第一行的内容;
- 接着复制第5-9位(已变成第一行的数据)到第10-14位(第三行),最终第三行也变成了第一行的内容,导致所有行都是第一行数据。
解决方案
要避免重叠覆盖,需要反向复制——先复制最下方的源行到目标行,再依次向上处理,确保源数据在被复制前不会被修改。
单行拆分复制(适合固定行数)
直接拆分两次独立的单行复制操作:
// 先复制第二行到第三行 span.Slice(1, 0, 1, w).CopyTo(span.Slice(2, 0, 1, w)); // 再复制第一行到第二行 span.Slice(0, 0, 1, w).CopyTo(span.Slice(1, 0, 1, w));
循环反向复制(适合任意行数)
如果数组行数更多,可用循环从下往上遍历处理每一行:
for (int i = h; i > 0; i--) { span.Slice(i-1, 0, 1, w).CopyTo(span.Slice(i, 0, 1, w)); }
修改后的完整测试代码
public class SpanTest { public static void Main() { int[,] array = { { 1, 2, 3, 4, 5 }, { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, }; var h = array.GetLength(0) - 1; var w = array.GetLength(1); Console.WriteLine($"slice height:{h} width: {w}\n-----------"); Span2D<int> span = array; Console.WriteLine($"原始数组:\n{span.ToStringMatrix()}-----------"); // 替换原来的CopyTo操作,改为反向单行复制 span.Slice(1, 0, 1, w).CopyTo(span.Slice(2, 0, 1, w)); span.Slice(0, 0, 1, w).CopyTo(span.Slice(1, 0, 1, w)); Console.WriteLine($"滚动后数组:\n{span.ToStringMatrix()}-----------"); } } public static class Utils { public static string ToStringMatrix<T>(this Span2D<T> arr) { var sb = new StringBuilder(); for (var i = 0; i < arr.Height; i++) { for (var j = 0; j < arr.Width; j++) { sb.Append($"{arr[i, j]} "); } sb.Append(Environment.NewLine); } return sb.ToString(); } }
运行结果
slice height:2 width: 5 ----------- 原始数组: 1 2 3 4 5 0 0 0 0 0 0 0 0 0 0 ----------- 滚动后数组: 1 2 3 4 5 1 2 3 4 5 0 0 0 0 0 -----------
内容的提问来源于stack exchange,提问作者MarkNS
相关产品推荐
相关产品推荐

