1

I have looked at multiple SO questions related to mine, as well as Googling, and I have been unable to find a solution that works for me.

Given a list of files, I am trying to cull all the non-cs ones, for reasons. I take the string array, convert to list, and iterate over the list, removing all the files I don't want by using list.Remove().

After the first removal, it errors out with

Collection was modified; enumeration operation might not execute

The code is:

string[] files = null;
            try
            {
                files = System.IO.Directory.GetFiles(currentDir);

                //Converting to list, to use list.Remove rather than rewriting entire array at each delete
                var list = new List<string>(files);
                foreach (string readFile in list)
                {
                    if (Path.GetExtension(readFile) != ".cs") //|| Path.GetExtension(readFile) != ".dll")
                    {
                        //remove, as we don't currently care about non cs files.
                        list.Remove(readFile);
                    }
                }

                //Converting back to string array for use in the rest of the program
                files = list.ToArray();
            }

I have also tried RemoteAt(), which produces the same error.

string[] files = null;
            try
            {
                files = System.IO.Directory.GetFiles(currentDir);

                //Converting to list, to use list.Remove rather than rewriting entire array at each delete
                var list = new List<string>(files);
                int i = 0;
                for(int i=0; i<list.Count();i++)
                {
                    if (Path.GetExtension(readFile) != ".cs") //|| Path.GetExtension(readFile) != ".dll")
                    {
                        //remove, as we don't currently care about non cs files.
                        list.RemoveAt(i);
                    }
                    i++;
                }

                //Converting back to string array for use in the rest of the program
                files = list.ToArray();
            }

Any recommendations for overcoming this error, as some of the directories will have over 500 files in them, and I want to avoid rewriting the string array as much as possible.

I have read the following SO questions:

How to remove item from list in C#?

C# error Collection was modified; enumeration operation might not execute

Enumerations Foreach Loop C#

"List.Remove" in C# does not remove item?

https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.list-1.remove?view=netframework-4.8

https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.list-1.removeat?view=netframework-4.8

GokuMizuno
  • 493
  • 2
  • 5
  • 14
  • 2
    If you only want `*.cs`, you can pass that to [`GetFiles`](https://learn.microsoft.com/en-us/dotnet/api/system.io.directoryinfo.getfiles?view=netframework-4.8#System_IO_DirectoryInfo_GetFiles_System_String_). – Blorgbeard Apr 29 '19 at 16:25
  • 2
    Or you can replace your for-loop with a quick LINQ expression, something like `return files.Where(t=>Path.GetExtension(t) == ".cs").ToArray();` – Blorgbeard Apr 29 '19 at 16:26
  • XY problem. @Blorgbeard got the point. – CSDev Apr 29 '19 at 16:37

3 Answers3

2

You can also use a for loop in reverse order so that removed entries do not effect the loop.

for (int x = list.Count-1; x >= 0; x--)
{
  string readFile = list[x];
  // ...
  list.Remove(readFile);
}
Troy Mac1ure
  • 637
  • 4
  • 9
1

If I change

foreach (string readFile in list)

to

foreach (string readFile in list.ToList())

it works.

My guess is that the list.Remove alters the original list, and invalidates the enumeration.

GokuMizuno
  • 493
  • 2
  • 5
  • 14
  • 2
    "*My guess is that the list.Remove alters the original list, and invalidates the enumeration.*" -- this is correct – canton7 Apr 29 '19 at 16:22
1

You can use the RemoveAll method on List:

list.RemoveAll(readFile => Path.GetExtension(readFile) != ".cs");

This will remove everything that matches your predicate, and will return the number of items it removed.

Sean
  • 60,939
  • 11
  • 97
  • 136