我无法理解为什么包含的多个调用会为同一个可枚举的返回相同参数的不同值。 虽然我知道可以修改集合,从而在后续调用中更改结果,但这可以在这里排除。
在MVC视图中考虑以下(精简的)代码。 这样做的目的是显示一个复选框列表(因为没有HTML帮助程序),并通过模型的属性确定打开视图时应该检查哪些。
@foreach (var d in Model.AllDomains) {
bool isChecked = Model.Project.Domains.Contains(d.ID);
<input @(isChecked ? "checked=\"checked\" " : "")type="checkbox" value="@d.ID" />
// more stuff here
}
将其更改为使用实际的List会使整个过程按预期工作:
var tmp = Model.Project.Domains.ToList();
@foreach (var d in Model.AllDomains) {
bool isChecked = tmp.Contains(d.ID);
<input @(isChecked ? "checked=\"checked\" " : "")type="checkbox" value="@d.ID" />
// more stuff here
}
以下是绑定到我的视图的模型(再次简化以使其更具可读性):
public ProjectVM GetByID(int id) {
return new ProjectVM {
Project = new Project {
... // Other properties here
Domains = from d in MyObjectModel.Projects[id].Domains
select d.ID
},
AllDomains = from d in MyObjectModel.Domains
orderby d.Name
select new {
ID = d.ID,
Name = d.Name
}
};
}
现在,在调试时我知道Model.Project.Domains
将包含正确数量的条目以及正确的值,在方法上调用.Contains()会返回任意结果 - 无论是真还是假。
实际上,如果我将带有Contains()调用的行多次放入调试器的“Watch”选项卡中,即使使用硬编码参数(例如4),结果也会从true
中交替出来每次通话都要false
。
这里发生了什么,我忽略了什么?
由于Model.Project.Domains的实例化方式,其实际类型为WhereSelectEnumerableIterator<T>
,但这实现了IEnumerable<T>
,因此不应该是一个问题......
答案 0 :(得分:1)
问题的根本原因似乎是我们的对象模型的基础类中的Enumerator的一个草率/不寻常的实现,这使得GetEnumerator()
返回一个已经在前一次调用中使用的迭代器
由于Contains()
在找到第一个匹配项后停止迭代集合,如果搜索到的值在上一次迭代中已经搜索过的部分中,它将在这样的枚举器上返回false。
Contains()
的否定结果导致枚举器在内部重置,这解释了我原始帖子中描述的“切换”结果。