Moving the list, follow the method: is it possible to expand?

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 go through the full structure and execute the method for each element.

How can I create an extension for IEnumerable for such a move function.

Wonderfull will be something like this

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

Or is it impossible, and I need to create a special method in my business logic?

Many thanks.

+4
source share
5 answers

Do you mean the extension method on IEnumerable<Employee> ? This is certainly possible:

 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 employees, etc. employee.Employees.Traverse(action, predicate); } } 

This should be in a static, not general, not nested class.

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

EDIT: Here's a more generalized 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); } } 

Then you call it with:

 employees.Traverse(e => Save(e), e => e.Employees); 
+6
source

I assume that your main class should be Employer , not 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); } } } 
+2
source

I'm not sure what your parameters should indicate, but if the second parameter is a predicate, you can 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 could also add that such a function already exists on List<T> , so if ToList not a problem, you could do

 employeList.Where(e => e.Employees.Count > 0).ToList().ForEach(Save); 
0
source

You can do this 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); } } 
0
source

When passing through an action, it can be useful, it is not as flexible as an iterator, which lists all the elements in the tree structure, making them available for use with other LINQ operators:

 public static class ExtensionMethods { // Enumerate all descendants of the argument, // but not the argument itself: public static IEnumerable<T> Traverse<T>( this T item, Func<T, IEnumerable<T>> selector ) { return Traverse<T>( selector( item ), selector ); } // Enumerate each item in the argument and all descendants: public static IEnumerable<T> Traverse<T>( this IEnumerable<T> items, Func<T, IEnumerable<T>> selector ) { if( items != null ) { foreach( T item in items ) { yield return item; foreach( T child in Traverse<T>( selector( item ), selector ) ) yield return child; } } } } // Example using System.Windows.Forms.TreeNode: TreeNode root = myTreeView.Nodes[0]; foreach( string text in root.Traverse( n => n.Nodes ).Select( n => n.Text ) ) Console.WriteLine( text ); // Sometimes we also need to enumerate parent nodes // // This method enumerates the items in any "implied" // sequence, where each item can be used to deduce the // next item in the sequence (items must be class types // and the selector returns null to signal the end of // the sequence): public static IEnumerable<T> Walk<T>( this T start, Func<T, T> selector ) where T: class { return Walk<T>( start, true, selector ) } // if withStart is true, the start argument is the // first enumerated item in the sequence, otherwise // the start argument item is not enumerated: public static IEnumerable<T> Walk<T>( this T start, bool withStart, Func<T, T> selector ) where T: class { if( start == null ) throw new ArgumentNullException( "start" ); if( selector == null ) throw new ArgumentNullException( "selector" ); T item = withStart ? start : selector( start ); while( item != null ) { yield return item; item = selector( item ); } } // Example: Generate a "breadcrumb bar"-style string // showing the path to the currently selected TreeNode // eg, "Parent > Child > Grandchild": TreeNode node = myTreeView.SelectedNode; var text = node.Walk( n => n.Parent ).Select( n => n.Text ); string breadcrumbText = string.Join( " > ", text.Reverse() ); 
0
source

Source: https://habr.com/ru/post/1316166/


All Articles