在foreach循环中使用Point.Offset方法修改Point数组的疑问及最优方案
解决C#中Point数组的Offset修改问题
哈哈,这个问题我当初刚学C#的时候也踩过坑!核心原因是**Point是值类型**,而foreach遍历数组时拿到的是每个元素的副本——你调用Offset修改的只是这个临时副本,原数组里的Point根本不会有变化。下面给你几种靠谱的方式,把偏移后的Point正确存回MyPoints数组:
方法1:用for循环(最直接易读,完全合理)
这其实是非常正统的写法,一点都不算“不正确”,反而可读性拉满:
using System; using System.Drawing; // 注意要引用System.Drawing命名空间 class Program { static void Main() { Point[] MyPoints = { new Point(1, 1), new Point(2, 2) }; int offsetX = 5, offsetY = 5; for (int i = 0; i < MyPoints.Length; i++) { // 取出数组里的Point副本 var currentPoint = MyPoints[i]; // 调用Offset修改副本的坐标 currentPoint.Offset(offsetX, offsetY); // 把修改后的副本存回原数组的对应位置 MyPoints[i] = currentPoint; } // 验证结果 foreach (var p in MyPoints) { Console.WriteLine($"X: {p.X}, Y: {p.Y}"); } } }
方法2:用LINQ创建新数组(简洁的函数式写法)
如果你喜欢更简洁的代码,可以用LINQ生成修改后的新数组,再赋值回原变量:
using System; using System.Drawing; using System.Linq; class Program { static void Main() { Point[] MyPoints = { new Point(1, 1), new Point(2, 2) }; int offsetX = 5, offsetY = 5; // 遍历每个Point,修改后生成新数组 MyPoints = MyPoints.Select(p => { p.Offset(offsetX, offsetY); return p; }).ToArray(); // 验证结果 foreach (var p in MyPoints) { Console.WriteLine($"X: {p.X}, Y: {p.Y}"); } } }
这种方式适合不需要保留原数组的场景,代码看起来更清爽。
方法3:用Span<T>高效修改(.NET Core/.NET 5+适用)
如果你的项目基于.NET Core或.NET 5及以上版本,可以用Span<T>来直接操作数组元素,避免不必要的副本,效率更高:
using System; using System.Drawing; class Program { static void Main() { Point[] MyPoints = { new Point(1, 1), new Point(2, 2) }; int offsetX = 5, offsetY = 5; // 用AsSpan()获取数组的跨度,ref var直接引用数组里的元素 foreach (ref var p in MyPoints.AsSpan()) { p.Offset(offsetX, offsetY); // 直接修改原数组的元素,无需赋值 } // 验证结果 foreach (var p in MyPoints) { Console.WriteLine($"X: {p.X}, Y: {p.Y}"); } } }
这里的ref var让我们直接拿到数组中元素的引用,调用Offset时直接修改原数组里的实例,不需要额外的赋值步骤,性能最优。
总结一下:如果追求简单易读,for循环完全是正确选择;喜欢简洁就用LINQ;追求性能的话,Span<T>是最佳方案~
内容的提问来源于stack exchange,提问作者Ndnes
相关产品推荐
相关产品推荐

