在 LINQ 语句中创建新对象时,例如:
var list = new List<string>() { "a", "b", "c" };
var created = from i in list select new A();
A 类看起来像这样:
class A
{
public string Label;
}
然后使用 foreach 循环修改 A 中的属性:
foreach (var c in created) {
c.Label = "Set";
}
为什么之后访问
IEnumerable
中的对象时没有设置值。例如。以下断言失败:
Assert.AreEqual("Set", created.ElementAt(2).Label);
我想知道为什么会发生这种情况。我希望 foreach 语句执行查询,并触发对象的创建。 MSDN 文档指出:“查询的执行被推迟,直到在 foreach 或 For Each 循环中迭代查询变量”。
我已使用 .NET 4.5 和 Mono 3.2.0 重现了此行为。在访问创建的对象之前调用
ToList
上的 IEnumerable
可以解决这个问题。
发生这种情况是因为
created
是查询,而不是结果。因此,每次枚举它时,您都会从头开始重新评估 Select
。
如果您希望它起作用,请使
created
成为一个实际列表,而不仅仅是代表查询的 IEnumerable
。
例如添加:
created = created.ToList();
你说:
我希望 foreach 语句执行查询,并触发对象的创建
这正是正在发生的事情。 问题是每次迭代
created
时都会创建对象,而不仅仅是第一次。 由于 ElementAt()
方法会迭代 created
,因此它只是再次创建新的 A
。
很多年后
据我了解,停留在一个循环中,对链接到foreach的Linq的查询。 我遇到过代码没有执行的情况,在调试中它被暂停了:
For Each Item In dtDatos.Rows
Dim Str = String.Join(",", (From Dl In Ndtt Where Dl.Field(Of Integer)("MRP") = Item("MRP") And Dl.Field(Of Integer)("ProductID") = Item("ProductID") Select Dl.Field(Of Integer )("OrdenPid")).Distinct.ToList)
Item("Folio") = Str
Next
我通过将查询的比较值作为变量而不是作为 forach 项的一部分来解决这个问题,然后执行它。
Dim A As Integer
Dim B As Integer
For Each Item In dtDatos.Rows
A = Item("MRP")
B = Item("ProductID")
Item("Folio") = String.Join(",", (From Dl In Ndtt Where Dl.Field(Of Integer)("MRP") = A And Dl.Field(Of Integer)("ProductID") = B Select Dl.Field(Of Integer)("OrdenPid")).Distinct.ToList)
Next