Nested foreach loops to get info from nested lists using C#

An object EmployeeInfoDocument contains a list of groups. Each group holds a list of employees. I am trying to use a nested foreach loop to write the values out to an XML file. It seems that I have the syntax wrong on the inner foreach loop. Visual Studio is giving me the following error:

foreach statement cannot operate on variables of type 'InfoObjects.Group' because 'InfoObjects.Group' does not contain a public definition for 'GetEnumerator'

How do I pull info from each employee within the groups? I'm extremly new to C#.

Any insight would be appreciated.

namespace InfoObjects
{
    public class EmployeeInfoDocument
    {
        private List<Group> _groups = new List<Group>();
        public List<Group> Groups
        {
            get { return _groups; }
            set { _groups = value; }
        }
    }
    public class Group
    {
        private string _text = string.Empty;
        private List<Employee> _info = new List<Employee>
        public Group()
        {
        }
        public string Text
        {
            get {return _text; }
            set { _text = value; } 
        }
        public List<Employee> Employees
        {
            get { return _info }
            set { _info = value; }
        }
    }

    public class Employee
    {
         private string _name = string.Empty;
         private string _department = string.Empty;
         public Employee()
         {
         }
         public string Name
         {
         get { return _name;}
         set { _name = value;}
         }
         {
         public string Department
         {
         get { return _department};
         set { _department = value;}
         }
    }
}


namespace UI
{
    public partial class Mainform: Form
    {
        private void OnSave(object sender, EventArgs e)
        {
            SaveFileDialog saveFileDialog = new SaveFileDialog();
            saveFileDialog.RestoreDirectory = false;
            saveFileDialog.InitialDirectory = Assembly.GetExecutingAssembly().Location;
            saveFileDialog.Filter = "Employee Files|*.xml";
            saveFileDialog.DefaultExt = "xml";
            using (saveFileDialog)
            {
                if (saveFileDialog.ShowDialog(this) != DialogResult.OK)
                    return;
            }

            using (XmlWriter xmlw = XmlWriter.Create(saveFileDialog.FileName))
            {
                EmployeeInfoDocument k = new EmployeeInfoDocument();
                List<Group> myList = k.Groups;
                xmlw.WriteStartDocument();
                xmlw.WriteStartElement("EmployeeInfo");
                foreach (Group group in EmployeeInfoMgr.Document.Groups)
                {
                    xmlw.WriteStartElement("Group Name");
                    xmlw.WriteString(group.Text);
                    foreach (Employee employee in group)
                    {
                        xmlw.WriteStartElement("Employee Name");
                        xmlw.WriteString(employee.Name);
                        xmlw.WriteEndElement();
                        xmlw.WriteStartElement("Employee Department");
                        xmlw.WriteString(employee.Department);
                        xmlw.WriteEndElement();
                     }
                    xmlw.WriteEndElement();
                 }
                 xmlw.WriteEndElement();
                 xmlw.WriteEndDocument();
            }
        }
    }
}

Thanks again. I've been stuck on this for hours now.

Edited: Missing semi-colons (Terribly sorry!)

Jon Skeet
people
quotationmark

So this is your problem:

foreach (Group group in ...)
{
    ...
    foreach (Employee employee in group)
    {
    }
}

The compiler can't use foreach over group because it has no idea what you'd iterate over. You either need to implement IEnumerable<T> (or at least provide an appropriate GetEnumerator() method) or specify that you actually want to iterate over the employees in the group:

foreach (Employee employee in group.Employees)

The latter is less of a change, of course, but if you want to be able to just iterate over a group, you can implement it like this:

public class Group : IEnumerable<Employee>
{
    public string Text { get; set; }
    public List<Employee> Employees { get; set; }

    public IEnumerator<Employee> GetEnumerator()
    {
        return Employees.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

Notes:

  • I've replaced the properties with automatically-implemented properties, given that you were just using a field in a trivial way
  • I've removed the parameterless constructor which the compiler will provide by default
  • When implementing IEnumerable<T>, you also need to implement the non-generic IEnumerable, which I've done with explicit interface implementation as the GetEnumerator method clashes with the one in IEnumerable<T>.
  • At the moment there's very little encapsulation here - the list can be changed directly, for example. You could consider hiding the list, but keeping a field for the list (initializing it yourself) and having an Add(Employee) method or whatever you require.

people

See more on this question at Stackoverflow