You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在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.

火山引擎 最新活动