在列表和数组中按索引获取struct项

时间:2015-12-04 15:06:31

标签: c# arrays

当我使用struct的数组(例如System.Drawing.Point)时,我可以逐个索引并更改它。

例如(此代码工作正常):

Point[] points = new Point[] { new Point(0,0), new Point(1,1), new Point(2,2) };
for (int i = 0; i < points.Length; i++)
{
    points[i].X += 1;
}

但是当我使用List时它不起作用:

  

无法修改返回值   &#39; System.Collections.Generic.List.this [INT]&#39;   因为它不是变量

示例(此代码无法正常工作):

List<Point> points = new List<Point>  { new Point(0,0), new Point(1,1), new Point(2,2) };
for (int i = 0; i < points.Count; i++)
{
    points[i].X += 1;
}

我知道当我按索引获取列表项时,我得到了它的副本和编译器提示我没有提交错误,但为什么数组索引的元素工作方式不同?

2 个答案:

答案 0 :(得分:4)

这是因为数组 points[i]显示了对象所在的 。换句话说,数组的基本points[i]是内存中的指针。因此,您在内存中执行 on-the-record 操作,而不是在某些副本上执行。

List<T>不是这种情况:它在内部使用数组,但通过方法进行通信,导致这些方法将值复制出内部数组,显然修改这些副本不会很有道理:你没有立即忘记它们,因为你没有将副本写回内部数组。

解决这个问题的方法是,正如编译器建议的那样:

(3,11): error CS1612: Cannot modify a value type return value of `System.Collections.Generic.List<Point>.this[int]'. Consider storing the value in a temporary variable

所以你可以使用以下“技巧”:

List<Point> points = new List<Point>  { new Point(0,0), new Point(1,1), new Point(2,2) };
for (int i = 0; i < points.Count; i++) {
    Point p = points[i];
    p.X += 1;
    points[i] = p;
}

因此,您将副本读入临时变量,修改副本,然后将其写回List<T>

答案 1 :(得分:1)

原因是结构是值类型,因此当您访问列表元素时,您实际上将访问由列表的索引器返回的元素的中间副本。

换句话说,使用List<T>时,您正在创建副本。

MSDN

  

错误消息

     

无法修改'expression'的返回值,因为它不是a   变量

     

尝试修改作为结果的值类型   中间表达。因为值不是持久化的,所以是值   将保持不变。

     

要解决此错误,请将表达式的结果存储在   中间值,或使用中间值的引用类型   表达

解决方案:

List<Point> points = new List<Point>  { new Point(0,0), new Point(1,1), new Point(2,2) };
for (int i = 0; i < points.Count; i++)
{
    Point p = points[i];
    p.X += 1;
    //and don't forget update the old value, because we're using copy
    points[i] = p;
}