当前位置: 首页 > 知识库问答 >
问题:

foreach和linq查询-需要帮助,请尝试理解

汪才英
2023-03-14

我有一个linq查询,我在foreach循环中迭代其结果。

第一个是一个从表布局面板中获取控件集合的查询,然后我遍历该集合并从表布局面板中删除控件,因此:

var AllItems = (from Item in this.tableLayoutPanel1.Controls.OfType<ItemControl>()
                select Item);

foreach (ItemControl item in AllItems)
{
    Trace.WriteLine("Removing " + item.ToString());
    this.tableLayoutPanel1.Controls.Remove(item);
    item.Dispose();
}

上面的操作并不像我预期的那样(即抛出一个错误),它只删除了一半的控件(奇数的控件)。似乎在每次迭代中,AllItems都会减少其自身,尽管底层集合正在修改,但不会抛出错误。

如果使用字符串数组执行Similar:

        string[] strs = { "d", "c", "A", "b" };
        List<string> stringList = strs.ToList();

        var allitems = from letter in stringList
                       select letter;

        foreach (string let in allitems)
        {
            stringList.Remove(let);

        }

这次Visual studio抛出一个错误(如预期的那样),抱怨基础集合已更改。

为什么第一个例子不爆炸?

这里有一些关于迭代器/IEnumerable的东西我不理解,我想知道是否有人可以帮助我理解linq和foreach在幕后发生了什么。

(我知道我可以通过AllItems.ToList()解决这两个问题;在我迭代之前,我想理解为什么第二个示例会抛出错误,而第一个不会)

共有3个答案

谭俊
2023-03-14

试试这个:

var AllItems = (from Item in this.tableLayoutPanel1.Controls.OfType<ItemControl>() 
                select Item);  


  int totalCount = AllItems .Count;
   for (int i = 0; i < totalCount; i++)
       {
           AllItems .RemoveAt(0);
        }
谷泽宇
2023-03-14

所以在我的第一种情况下,linq表达式是在每一次foreach循环的迭代中被重新计算的吗?还是linq从tablelayoutpanel.controls集合中获得IEumator?

把它想象成这样,这就是你们两个案例中发生的事情:

    foreach (string l in (from letter in stringList select letter)) 
    { 
        stringList.Remove(l); 
    } 

上面的伪代码说明,当您尝试删除一个项目时,您实际上是在枚举stringList集合。Reed的意思是,在第二种情况下,stringList的枚举器确保在枚举过程中没有人干扰它。

他说,在你的控件的情况下,控件枚举器很乐意继续,不检查是否有人在篡改它的数据

为了完整性,请比较这两个示例:

每次触摸字母(包括我们在foreach循环中的时间)时,都将重新评估对字母的查询:

    IEnumerable<string> letters = from letter in stringList select letter);

    // everytime we hit this we're going to hit the stringList collection
    foreach (string l in letters) 
    { 
        stringList.Remove(l); 
    } 

此查询使用ToList()立即填充字母,我们将不再接触foreach循环中的stringList集合。

    List<string> letters = (from letter in stringList select letter).ToList()

    // because we ran ToList(), we will no longer enumerate stringList
    foreach (string l in letters) 
    { 
        stringList.Remove(l); 
    } 
酆英达
2023-03-14

为什么第一个例子不爆炸?

tableLayoutPanel1中的IEnumerator实现。控件未执行正确的检查以查看集合是否已修改。这并不意味着它是一个安全的操作(因为结果不合适),而是该类没有以引发异常的方式实现(它可能应该这样做)。

通过列表枚举时引发的异常

请注意,这是List的一个不错的功能

只要集合保持不变,枚举数就保持有效。如果对集合进行了更改,例如添加、修改或删除元素,则枚举器将不可恢复地失效,并且其行为未定义

虽然没有契约要求抛出异常,但当您进入“未定义行为”领域时,这样做对实现是有益的

在本例中,TableLayoutControlCollection类枚举器实现没有执行额外的检查,因此您可以看到当您使用“行为未定义”的功能时会发生什么(在这种情况下,它会删除其他控件。)

 类似资料:
  • 问题内容: 怀疑在VBA ADO和Sql查询中… 我有2张纸,即adodc1,adodc2(在一本工作簿中) 在adodc1中具有“名称”,“部门”列,有时其具有“ Sect”列 在adodc2中具有“名称”,“部门”,“宗派”列 我想要的是当我运行Query..Vba时需要检查adodc1是否具有Sect列。 要返回为空值.. 下面的代码取自“”,根据我的需要进行了更改 它将执行的工作是来自两张

  • 我的问题类似于SQL选择组查询。但是架构发生了变化,我想要不同的结果,如下所述。给定链接的解决方案没有给我正确的解决方案。您可以使用SQL小提琴来解决这个问题。 下面是我的桌子 表1 现在,我想显示每个产品的两个最低金额,如果金额相同,那么任何人都按照升序排列... 所以我想构建单个SQL查询,它给我的结果如下。 请帮我建立这样的查询。

  • 编写一个查询以显示staffid、费用代码、专科id、专科名称、会诊日期、患者号和到期日将使用会诊日期+21计算 STAFFID NOT NULL CHAR(2) FIRSTNAME VARCHAR2(20) LASTNAME VARCHAR2(20) 角色VARCHAR2(15) 性别CHAR(1) 日期连接日期 DATELEFT DATE SQL>描述staffspeciality错误: OR

  • 问题内容: 我正在使用Glassfish和JSF构建我的第一个Java EE Web应用程序。我对条件查询还很陌生,我有一个需要执行的查询,但是javaee6教程的示例似乎有些稀疏。无论如何,我很难创建查询。 目标:我想让公司存储最多的文件。公司与Documents有OneToMany关系。文档与多个表具有ManyToOne关系,“用户类型”列将它们区分开。 MySQL查询: 谢谢 --updat

  • 我有这张桌子: 这是我的SQL查询: 我想要的查询是: > 我希望获得符合某些条件的记录,特别是字段在最近24小时内的记录 我需要获得紧接在#1中的记录之前的记录 将#1中的结果进一步过滤到其价格列在记录的历史记录中具有不同值(而不是-1)的记录 我面临的问题是查询太慢了。我有一百万张唱片。执行查询大约需要2分钟。我猜GROUP BY会使查询变慢。我想我需要做一个综合指数,但我不知道怎么做。 解释

  • 问题内容: 好吧,我可能也已在较早之前发布了此内容,但到目前为止仍找不到答案,因此请帮助我解决这个问题。 我的数据库结构: ATT (表) Act_ID(PK) Assigned_To_ID(FK,请参阅) Project_ID(FK,请参阅) Product_ID(FK,请参阅) 状态(可以是) 产品表 产品编号(PK) 产品名称 项目表 Project_ID(PK) 项目名 员工表 Emp_I