Search code examples
c#foreachpass-by-referenceienumerablepass-by-value

Change an object in a list of objects by using foreach over a smaller list of the same objects


Im trying to use a foreach loop to change the values in objects in that list. However I need one list that doesnt change to enumerate over, and the main list to be changed as I do so. No matter what I try I run into an error because it is changing the object in the list I am enumerating over.

public static void GetHtml(Site website)
    {
        IEnumerable<Page> pages = new List<Page>();
        pages = website.PageList.Where(c => !c.Checked);
        WebClient client = new WebClient();
        foreach (Page page in pages)
        {
            try
            {
                page.Html = client.DownloadString(page.PageUrl);
                ParseHtml(page);
                ParseLinks(page, website);
                page.Valid = true;
                page.Checked = true;
            }
            catch
            {
                page.Valid = false;
                page.Checked = true;
            }
        }
    }

The site object contains a List where I want to modify the values of the Page objects, but I dont need to modify the list of Page I am enumerating over. I thought instantiating a new list would do the job, but obviously not.


Solution

  • Try this code, the ToList() method will create a the new List you want

    public static void GetHtml(Site website)
    {
        // you don't need to instantiate a new List, because the after the next statement the variable pages will hold a different object
        // and the List you created will be garbage
        IEnumerable<Page> pages;
        // the .ToList() will instantiate a new List with all the results of the Where
        pages = website.PageList.Where(c => !c.Checked).ToList();
        WebClient client = new WebClient();
        foreach (Page page in pages)
        {
            try
            {
                page.Html = client.DownloadString(page.PageUrl);
                ParseHtml(page);
                ParseLinks(page, website);
                page.Valid = true;
                page.Checked = true;
            }
            catch
            {
                page.Valid = false;
                page.Checked = true;
            }
        }
    }