2015-12-04 72 views
7

当我使用struct s的数组(例如System.Drawing.Point)时,我可以通过索引获取项目并对其进行更改。通过列表和数组中的索引获取struct项目

例如(此代码做工精细):

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它不工作:

无法修改 返回值“System.Collections.Generic.List 。这[INT]” ,因为它不是一个可变

实施例(该代码不工作精细):

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; 
} 

我知道,当我通过索引获取列表项我得到了它的复制和编译器提示,我没有犯一个错误,但为什么要采取数组索引的元素原理不同?

+3

http://stackoverflow.com/questions/14945118/cant-change-structs-members-value-inside-generic-collections#answer-14958238 –

回答

4

这是因为对于阵列points[i]显示其中对象位于。换句话说,基本上points[i]阵列是一个指针在内存中。因此,您在内存中执行记录中的操作,而不是在某些副本上。

这不是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

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

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

MSDN

错误消息

无法修改“表达”的返回值,因为它不是一个 可变

的是为了修改,这是结果的值类型尝试中间表达式的一个 。由于该值未被保留,因此值 将保持不变。

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

解决方案:

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; 
} 
+3

这不会改变列表中的值我很害怕:note那'结构'意味着你*复制记录的内容。所以'p'是一个副本,不会对原始列表产生任何影响。 –

+1

@CommuSoft的确,你是对的。 Bu我已经修复了它=) – isxaker

+0

@isxakar:好吧取+1;) –