我有一个名为ACTIVITY的课程。该类包含一个Laps列表,每个Lap都有一个TRACPOINTS集合。
ACTIVITY - 很多 - > LAPS ---很多 - > TRACPOINTS。
每当我查看TRACPOINTS集合时,我都会获得所有TRACPOINTS的列表。但是当我修改那些原件时,原件不会被修改,因为它是副本。
有没有什么方法可以改变我在每个圈子的Tracpoints列表中对变平的tracpoints做出的改变?
答案 0 :(得分:1)
只要TRACPOINT是一个结构,就不可能以任何合理的方式。
每当将struct variable或field的值赋给另一个变量或字段时,都会复制其内容。将它作为方法参数传递或从方法返回它同样适用,它的值被复制。这是价值语义[1]。将此与像int
这样的原子类型进行比较,它们也具有值语义。您可能希望以下代码打印2而不是3。
static function Change(int j) { j = 3; }
static void Main(string[] args) {
int i = 2;
Change(i);
System.Console.WriteLine(i);
}
如果执行SelectMany,集合中的每个值可能都会分配给某个临时局部变量,然后从迭代器(SelectMany)返回,因此它会被复制,实际上可能会在从迭代器出来之前复制很多次。所以你要更新的是结构的副本。与示例中一样,您不是更改变量i
,而是将其副本存储在变量j
中。
这就是结构应该是不可变的原因。它们应该只有getter,而不是在你的struct中使用getter和setter属性。要更改结构的属性值,可以实现复制整个原始结构的方法,更改所需属性的值并返回新的结构实例。事实上,它的副本将被退回。例如:
struct S {
int f;
public int F { get { return this.f; } }
public S SetF(int newVal) {
var s = new S();
s.f = newVal;
return s;
}
}
var x = new S();
x = x.SetF(30);
也就是说,用指针和不安全的C#实现你想要的东西是可能的,但是相信我,将结构更改为类会更容易,因此它们具有引用语义而不是值语义,或者保持他们结构,但让他们不变,不使用Linq,但旧学校循环。如果你想在这样的场景中使用Linq这样的东西,你可能不关心结构和类之间的性能差异......
[1] http://msdn.microsoft.com/en-us/library/aa664472(v=vs.71).aspx