1

我无法理解为什么多次调用 Contains会为同一 enumerable 上的同一参数返回不同的值。虽然我知道可以修改集合,从而在后续调用中更改结果,但可以在这里排除。

考虑 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 被实例化的方式,它的实际类型是 a WhereSelectEnumerableIterator<T>,但是这个实现IEnumerable<T>不应该是一个问题......

4

1 回答 1

1

似乎问题的根本原因是我们的对象模型的基础类中 Enumerator 的草率/异常实现,这使得GetEnumerator()返回一个迭代器,该迭代器已经在之前的调用中使用

由于Contains()在找到第一个匹配项后停止迭代集合,如果搜索的值在前一次迭代中已经搜索过的部分中,它将在这样的 Enumerator 上返回 false。一个否定的结果Contains()导致枚举器在内部重置,这解释了我原来的帖子中描述的“切换”结果。

于 2013-07-23T06:30:36.783 回答