使用LINQ查询数组元素后能否直接修改其值?
问题描述
我定义了一个存储SitSpot结构体的数组:
SitSpot[] _spots = new SitSpot[4];
SitSpot结构体的定义如下:
struct SitSpot { public SitSpot(Transform spot, bool isOccupied, int id) { IsOccupied = isOccupied; Spot = spot; Id = id; } public bool IsOccupied; public Transform Spot; public int Id; }
但当我通过LINQ查询获取元素并修改时,原数组中的元素根本没变化:
SitSpot spot = _spots.Where(x => x.IsOccupied != true).OrderBy(x => Vector3.Distance(x.Spot.position, driver.transform.position)).FirstOrDefault(); spot.IsOccupied = true;
目前我只能先修改这个查询到的元素,再通过索引重新赋值回数组:
SitSpot spot = _spots .Where(x => x.IsOccupied != true) .OrderBy(x => Vector3.Distance(x.Spot.position, driver.transform.position)) .FirstOrDefault(); spot.IsOccupied = true; int i = Array.FindIndex(_spots, x => x.Id == spot.Id); _spots[i] = spot;
想问下有没有办法直接访问数组内的元素并修改,不用修改后再重新赋值?
解决方案
问题出在**SitSpot是值类型(结构体)**——值类型在赋值、传递的时候会生成副本。LINQ的Where、FirstOrDefault这些方法返回的都是结构体的副本,你修改的只是这个副本的属性,原数组里的元素自然不会变。
要实现直接修改数组内的元素,有两种靠谱的办法:
1. 把SitSpot改成类(引用类型)
把struct换成class,这样LINQ查询返回的是对象的引用,修改引用的属性时,会直接作用于原数组里的对象:
class SitSpot { public SitSpot(Transform spot, bool isOccupied, int id) { IsOccupied = isOccupied; Spot = spot; Id = id; } public bool IsOccupied; public Transform Spot; public int Id; }
改完之后,原来的LINQ代码就能直接修改原数组的元素,不用再重新赋值。
2. 直接操作数组索引,避免生成副本
如果一定要用结构体,可以先找到目标元素的索引,直接通过索引访问数组元素并修改,跳过LINQ返回副本的步骤:
// 遍历数组找到距离最近的未被占用的位置索引 int targetIndex = -1; float minDistance = float.MaxValue; for (int i = 0; i < _spots.Length; i++) { if (!_spots[i].IsOccupied) { float distance = Vector3.Distance(_spots[i].Spot.position, driver.transform.position); if (distance < minDistance) { minDistance = distance; targetIndex = i; } } } // 找到后直接修改数组内的原元素 if (targetIndex != -1) { _spots[targetIndex].IsOccupied = true; }
这种方式直接操作数组的原始元素,不会产生副本,修改会立刻生效。
内容的提问来源于stack exchange,提问作者Berke Çakır
相关产品推荐
相关产品推荐

