0

I have wrote the following code inside my console application, the purpose is to loop through all the current sub-sites, and then loop through all the current lists. If the default list view contain a field called "global1" or "global2" to remove it from the view:

using (SPSite site = new SPSite(scurl))  //site collection url
            {
using (SPWeb web = site.OpenWeb(subsiteurl0)) //specific subsite url
            {
      SPWebCollection subWebs = web.Webs; //get all sites under specific subsites

  foreach (SPWeb subSite in subWebs)
                 {


      var l = subSite.Lists;
      var ll = l;
      foreach (SPList l2 in ll)
      {
         var defaultview = l2.DefaultView;
         if (defaultview != null)
         {
             if (defaultview.ViewFields.SchemaXml.Contains("global1"))
             {
                 defaultview.ViewFields.Delete("global1"); // #use internal column name
                 defaultview.Update();
             }
             if (defaultview.ViewFields.SchemaXml.Contains("global2"))
             {
                 defaultview.ViewFields.Delete("global2"); // #use internal column name
                 defaultview.Update();
             }

         }
      }

When I run this console application and a column is deleted from the list view, I will get the following exception :

Collection was modified; enumeration operation may not execute.

When the next loop iteration is reached :

 foreach (SPList l2 in ll)
  • Try to seperate the logic. Maybe first search for the fields and add it to some dictionary or string array. And at the end run the delete Method. – Ola Jan 5 '17 at 13:50
2

I think you should do it like this, using a for statement instead of a foreach statement:

using (SPSite site = new SPSite(scurl))  //site collection url
{
    using (SPWeb web = site.OpenWeb(subsiteurl0)) //specific subsite url
    {
        var websCount = web.Webs.Count;
        for (var i = 0; i < websCount; i++)
        {
            var subSite = web.Webs[i];

            var listsCount = subSite.Lists.Count;
            for (var j = 0; j < listsCount; j++)
            {
                var l2 = subSite.Lists[j];
                var defaultview = l2.DefaultView;
                if (defaultview != null)
                {
                    if (defaultview.ViewFields.SchemaXml.Contains("global1"))
                    {
                        defaultview.ViewFields.Delete("global1"); // #use internal column name
                        defaultview.Update();
                    }
                    if (defaultview.ViewFields.SchemaXml.Contains("global2"))
                    {
                        defaultview.ViewFields.Delete("global2"); // #use internal column name
                        defaultview.Update();
                    }

                }
            }
        }
    }
}

Edit: You cannot modify the collection using a foreach loop. You must use another technique like a for loop to get items in the collection.

An enumerator remains valid as long as the collection remains unchanged. If changes are made to the collection, such as adding, modifying, or deleting elements, the enumerator is irrecoverably invalidated and its behavior is undefined.

MSDN

  • but why i am getting the error when using foreach? could this error trying to indicate something important to me i should not do inside my list views?? ,, i mean if i use for instead of foerach then i can remove the field from the list views correctly.. but maybe i should try to fix the exception when using foreach() rather than simply replace foreach() with for to achieve this? did you understand my point ,, so can i keep using foreach() but overcome this exception ? – john Gu Jan 18 '17 at 0:29
  • 1
    "An enumerator remains valid as long as the collection remains unchanged. If changes are made to the collection, such as adding, modifying, or deleting elements, the enumerator is irrecoverably invalidated and its behavior is undefined." – Cecilia Jan 18 '17 at 6:57
  • 1
  • 1
    This means, that you cannot modify the collection using a foreach loop. You must use another technique like a for loop to get items in the collection. – Cecilia Jan 18 '17 at 7:02
2

You can't modify a collection using a foreach loop. Use a for loop.

On a mobile so hard to type this out. Try:

for(var l1 = 0; l1 < subSite.Lists.Count; l1++)
{
     var defaultview = l1.DefaultView;
     if (defaultview != null)
     {
         if (defaultview.ViewFields.SchemaXml.Contains("global1"))
         {
             defaultview.ViewFields.Delete("global1"); // #use internal column name
             defaultview.Update();
         }
         if (defaultview.ViewFields.SchemaXml.Contains("global2"))
         {
             defaultview.ViewFields.Delete("global2"); // #use internal column name
             defaultview.Update();
         }

     }
}
  • +1 for the correct answer, but a code sample might be helpful. – Dylan Cristy Jan 5 '17 at 14:01
  • @Bunzab can you advice how i can use for loop instead of foreach in my case? and which foreach you are talking about? – john Gu Jan 5 '17 at 14:14
  • 1
    The second one. See the edit. – Bunzab Jan 5 '17 at 14:49
  • @Bunzab but i need to access the lists based on the id is this correct ? something such as "var defaultview = l1[i].DefaultView;" ? is this correct? – john Gu Jan 5 '17 at 15:03
  • 1
    @Cecilia gave a good answer and follow up comment. – Bunzab Jan 18 '17 at 10:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.