LINQ选择许多-修改扁平集合

本文关键字:集合 修改 选择 许多 LINQ | 更新日期: 2023-09-27 18:09:36

我有一个名为ACTIVITY的类。该类包含一个圈的列表,每个圈都有一个tracpoint的集合。

活动————>圈——许多——> TRACPOINTS。

每当我平放TRACPOINTS集合时,我都会得到所有TRACPOINTS的列表。但是当我修改这些内容的时候,原件当然不会被修改,因为它是副本。

是否有任何方法,无论我对平面化跟踪点做了什么改变,在每一圈的跟踪点列表中都会发生变化?

LINQ选择许多-修改扁平集合

只要TRACPOINT是一个结构体,就不可能以任何合理的方式。

当你将struct变量或字段的值赋给另一个变量或字段时,它的内容将被复制。将其作为方法参数传递或从方法返回时也是如此,它的值将被复制。这是值语义[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和setter的属性,而应该只有getter。要改变结构体的属性值,可以实现复制整个原始结构体的方法,改变所需属性的值并返回新的结构体实例。事实上,它的副本会被归还。例子:

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来做一些像SelectMany这样的事情,你可能不太关心结构和类之间的性能差异…

[1] http://msdn.microsoft.com/en-us/library/aa664472 (v = vs.71) . aspx