如何在foreach循环中修改List中struct值类型的属性?
如何在foreach循环中修改值类型(struct)集合元素?
我希望以下代码能够正常运行:
foreach (Rect item in VM.Cubes) { VM.FallDown(ref item); } class VM { public void FallDown(ref Rect entity) { if ((entity.Y + entity.Height < 800)) { entity.Y++; } } }由于Rect是struct(值类型),只有通过引用传递参数调用方法时才能修改其Y属性。但foreach循环不允许修改遍历的元素,且VM.Cubes为List集合,我也无法使用常规for循环,请问该如何实现需求?
这是个非常典型的值类型集合修改场景,我给你几个针对性的解决方案,你可以根据自己的业务场景选择:
方案1:将Rect改为引用类型(class)
如果业务逻辑允许的话,这是最省心的方案。把Rect从struct改成class后,所有对对象属性的修改都会直接作用于集合中的实例,不需要处理值类型的拷贝问题:
// 把Rect改为class public class Rect { public int Y { get; set; } public int Height { get; set; } // 其他需要的属性... } // 此时foreach可以直接调用方法,甚至不需要ref参数 foreach (var item in VM.Cubes) { VM.FallDown(item); } class VM { public void FallDown(Rect entity) { if (entity.Y + entity.Height < 800) { entity.Y++; } } }
方案2:生成新集合替换原集合
如果必须保留Rect作为struct,又不能用常规for循环,你可以通过LINQ的Select方法生成一个包含修改后元素的新集合,再替换原集合:
VM.Cubes = VM.Cubes.Select(cube => { var tempCube = cube; VM.FallDown(ref tempCube); return tempCube; }).ToList();
这种方式的核心是先拷贝每个struct元素,修改拷贝后的实例,再将修改后的实例放入新集合,最后替换原集合。
方案3:用Span<T>直接操作底层内存(.NET Core/.NET 5+)
如果你的项目基于.NET Core或.NET 5及以上版本,可以利用Span<T>来直接访问List的底层数组,这样既能保留值类型的性能优势,又能直接修改集合中的元素:
var cubeSpan = VM.Cubes.AsSpan(); foreach (ref var item in cubeSpan) { VM.FallDown(ref item); }
这里的ref var会直接获取到集合中struct元素的引用,修改后会直接作用于原List的底层数组,不需要额外的拷贝或替换操作,效率非常高。
内容的提问来源于stack exchange,提问作者D.W.




