简体   繁体   English

帮助在C#中将foreach循环转换为while循环

[英]Help with converting foreach loop to while loop in c#

I had learnt by reading your great answers here, that it is not good practice deleting items from within a foreach loop, as it is (and I quote) "Sawing off the branch you're sitting on". 通过阅读您的出色答案,我了解到,从foreach循环中删除项目不是一个好习惯,因为(我引用)“锯掉您所在的分支”。

My code currently removes the text from the dropdownlist, but the actual item remains (just without text displayed). 我的代码当前从下拉列表中删除了文本,但实际的项目仍然存在(只是没有显示文本)。

In other words, it isn't deleting, and probably can't because you can't delete from within a foreach loop. 换句话说,它不是删除,并且可能无法删除,因为您不能从foreach循环中删除。

After hours of trying I am unable to get my head around a way of doing it. 经过数小时的尝试,我无法找到解决方法。

//For each checked box, run the delete code
for (int i = 0; i < this.organizeFav.CheckedItems.Count; i++)
{
    //this is the foreach loop
    foreach (ToolStripItem mItem in favoritesToolStripMenuItem.DropDownItems)
    {
        //This rules out seperators
        if (mItem is ToolStripMenuItem)
        {
            ToolStripMenuItem menuItem = mItem as ToolStripMenuItem;

            //This matches the dropdownitems text to the CheckedItems String
            if (((ToolStripMenuItem)mItem).Text.ToString() == organizeFav.CheckedItems[i].ToString())
            {
                //And deletes the item
                menuItem.DropDownItems.Remove(mItem);
            }
        }
    }
}

But it isn't deleting because it is within a foreach loop! 但是它没有删除,因为它在foreach循环中! I would greatly appreciate your help, and be truly amazed if anyone can get their head around this code :) 非常感谢您的帮助,如果有人能理解这段代码,我将感到非常惊奇:)

Kind Regards 亲切的问候

Fun with LINQ! LINQ的乐趣!

// Loop through the checked items, same as you did.
foreach (var checkedItem in this.organizeFav.CheckedItems)
{
    // Cast from IEnumerable to IEnumerable<T> so we can abuse LINQ
    var matches = favoritesToolStripMenuItem.DropDownItems.Cast<ToolStripItem>()
                  // Only items that the Text match
                  .Where(item => item.Text == checkedItem.Text)
                  // Don't match separators
                  .Where(item => item is ToolStripMenuItem)
                  // Select the keys for the later .Remove call
                  .Select(item => item.Name);

    // Loop through all matches        
    foreach (var key in matches)
    {
        // Remove them with the Remove(string key) overload.
        favoritesToolStripMenuItem.Remove(key);
    }
}

You don't need a foreach loop - just use a regular loop but go in reverse, start at the end and go to the beginning. 您不需要foreach循环-只需使用常规循环,然后反向进行,从末尾开始,然后再开始。

//For each checked box, run the delete code
for (int i = 0; i < this.organizeFav.CheckedItems.Count; i++)
{
    //this *replaces* the foreach loop
    for(int j = favoritesToolStripMenuItem.DropDownItems.Count - 1; j >= 0; j--)
    {
        ToolStripMenuItem menuItem = favoritesToolStripMenuItem.DropDownItems[j] as ToolStripMenuItem; 

        //This rules out seperators
        if (menuItem != null)
        {
            //This matches the dropdownitems text to the CheckedItems String
            if (menuItem.Text.ToString() == organizeFav.CheckedItems[i].ToString())
            {
                favoritesToolStripMenuItem.DropDownItems.Remove(menuItem);
            }
        }
    }
 }

this was @Kurresmack's code rearranged, i just coded it directly here in the page so excuse any small syntax error or anything obvious i overlooked (disclaimer: it is a sample!!) 这是@Kurresmack的代码,我只是在页面上直接对其进行了编码,因此请原谅任何小的语法错误或任何我忽略的明显错误(免责声明:这是示例!)

You can still treat favoritesToolStripMenuItem.DropDownItems as a collection like you were, but you don't have to enumerate over it using a foreach . 您仍然可以像对待favoritesToolStripMenuItem.DropDownItems一样将favoritesToolStripMenuItem.DropDownItems视为一个集合,但是不必使用foreach对其进行枚举。 This cuts down on a few lines of code, and it works because you are iterating it in reverse order, you will not get an index out of bounds exception. 这减少了几行代码,并且可以工作,因为您以相反的顺序对其进行了迭代,因此您将不会获得索引超出范围的异常。

Try something like this: 尝试这样的事情:

//For each checked box, run the delete code
for (int i = 0; i < this.organizeFav.CheckedItems.Count; i++)
        {
    List<ToolStripItem> toRemove = new List<ToolStripItem>();
//this is the foreach loop
            foreach (ToolStripItem mItem in favoritesToolStripMenuItem.DropDownItems)
            {

                //This rules out seperators
                if (mItem is ToolStripMenuItem)
                {
                    ToolStripMenuItem menuItem = mItem as ToolStripMenuItem;

             //This matches the dropdownitems text to the CheckedItems String
                    if (((ToolStripMenuItem)mItem).Text.ToString() == organizeFav.CheckedItems[i].ToString())
                    {
                        toRemove.Add(mItem);
                    }
                }
            }
        foreach(var item in toRemove)
        {
        favoritesToolStripMenuItem.DropDownItems.Remove(item);
        }
        }

To my mind, the way to make the code work is: 在我看来,使代码起作用的方式是:
1. Create an instance of the type the favoritesToolStripMenuItem.DropDownItems collection is. 1.创建一个类型为“ favoritesToolStripMenuItem.DropDownItems集合的实例。
2. In the foreach loop, add all items, you do not want to be removed, to that collection. 2.在foreach循环中,将所有不想删除的项目添加到该集合中。
3. Make favoritesToolStripMenuItem.DropDownItems to point to the new collection. 3.使favoritesToolStripMenuItem.DropDownItems指向新集合。 Or clear favoritesToolStripMenuItem.DropDownItems and load the items from the new collection to it. 或清除favoritesToolStripMenuItem.DropDownItems并将新集合中的项目加载到其中。

Hope this helps 希望这可以帮助

Instead of a foreach use a reverse for -Loop: 代替foreach for -Loop使用反向:

for(int reverseIndex = myList.Count - 1; reverseIndex >= 0; reverseIndex--)
{
    var currentItem = myList[reverseIndex];
    if(MatchMyCondition(currentItem))
    {
        myList.Remove(currentItem);
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM