views:

61

answers:

4

Hi,

i have a data structure like this

public class Employee
{
    public string Name { get; set; }
    public IEnumerable<Employee> Employees { get; private set; }
    // ...
}

Now i need to loop through the complete structure and execute a method on each item.

How can i create an extension on IEnumerable for such a traverse function.

Wonderfull would be something like this

employeList.Traverse(e => Save(e), e.Employees.Count > 0);

Or is it impossible and i have to create a special method in my business logic?

Thanks a lot.

+2  A: 

I'm assuming your main class should be Employer rather than Employee.

public static class EmployerExtensions
{
    public static void Traverse(this Employer employer, Action<Employee> action)
    {
        // check employer and action for null and throw if they are

        foreach (var employee in employer.Employees)
        {
            action(employee);
        }
    }
}

HTH,
Kent

Kent Boogaart
+5  A: 

Do you mean an extension method on IEnumerable<Employee>? That's certainly feasible:

public static void Traverse(this IEnumerable<Employee> employees,
                            Action<Employee> action,
                            Func<Employee, bool> predicate)
{
    foreach (Employee employee in employees)
    {
        action(employee);
        // Recurse down to each employee's employees, etc.
        employee.Employees.Traverse(action, predicate);
    }
}

This has to be in a static, non-generic, non-nested class.

I'm not sure what the predicate bit is for, mind you...

EDIT: Here's the more generalised form I think you were looking for:

public static void Traverse<T>(this IEnumerable<T> items,
                               Action<T> action,
                               Func<T, IEnumerable<T>> childrenProvider)
{
    foreach (T item in items)
    {
        action(item);
        Traverse<T>(childrenProvider(item), action, childrenProvider);
    }
}

You'd then call it with:

employees.Traverse(e => Save(e), e => e.Employees);
Jon Skeet
Yes thats what iam done. I try to build up a Extension for every IEnumerable (Enumerable<T>). but my problem is/was the loop over the childs (employee.Employees.Traverse) in the Extension.I first thought, i can create an Extension where i can put the "employee.employee" call from the calling (as lambda or something else).
K.Hoffmann
@k-hoffman: I've edited my answer to show that approach.
Jon Skeet
yes, wonderfull. great. thanks a lot
K.Hoffmann
A: 

I'm not sure what your parameters are supposed to signify, but if the second parameter is a predicate, you may want to do something like this:

public static void Traverse(this IEnumerable<T> source, Action<T> action, Func<T,bool> predicate) {
   foreach(T item in source.Where(predicate)) {
      action.Invoke(item);
   }
}

I might also throw in that there already is such a function, on List<T>, so if ToList is not an issue, you would be able to do

employeList.Where(e => e.Employees.Count > 0).ToList().ForEach(Save);
David Hedlund
A: 

You can do it with a simple extension method:

employeeList.ForEach(e => Save(e));

public static partial class IEnumerableExtensions
{
    /// <summary>
    /// Executes an <see cref="Action&lt;T&gt;"/> on each item in a sequence.
    /// </summary>
    /// <typeparam name="T">The type of the elements of <paramref name="source"/>.</typeparam>
    /// <param name="source">An <see cref="IEnumerable&lt;T&gt;"/> in which each item should be processed.</param>
    /// <param name="action">The <see cref="Action&lt;T&gt;"/> to be performed on each item in the sequence.</param>
    public static void ForEach<T>(
        this IEnumerable<T> source,
        Action<T> action
        )
    {
        if (source == null)
            throw new ArgumentNullException("source");
        if (action == null)
            throw new ArgumentNullException("action");

        foreach (T item in source)
            action(item);
    }
}
Toby