2010-07-19 21 views
4

我有這樣遍歷一個列表,執行一個方法:擴展可能嗎?

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

的數據結構現在我需要遍歷的完整結構和在每個項目上執行的方法。

如何在IEnumerable上爲這種遍歷函數創建擴展。

WONDERFULL會是這樣的

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

抑或是不可能的,我要創建我的業務邏輯的特殊方法?

非常感謝。

回答

6

你的意思是擴展方法IEnumerable<Employee>?這當然是可行的:

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); 
    } 
} 

這必須在靜態,非泛型,非嵌套類。

我不知道謂詞位是什麼,你要知道...

編輯:這裏是更廣義的形式,我認爲你是在尋找:

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); 
    } 
} 

你再與調用它:

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

是的,這就是我做了什麼。我嘗試爲每個IEnumerable構建一個擴展(Enumerable )。但我的問題是/是擴展中的孩子(employee.Employees.Traverse)循環。 我首先想到的,我可以創建一個擴展,我可以從調用(如lambda或其他)調用「employee.employee」調用。 – Khh 2010-07-19 13:48:00

+0

@ k-hoffman:我編輯了我的答案以顯示該方法。 – 2010-07-19 13:51:34

+0

是的,很有意思。大。非常感謝 – Khh 2010-07-19 17:55:55

2

我假設你的主類應該是Employer而不是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); 
     } 
    } 
} 
0

我不知道你的參數都應該意味着什麼,但如果第二個參數是謂語,你可能想要做這樣的事情:

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); 
    } 
} 

我可能也扔在已經有這樣的功能,在List<T>,所以如果ToList是不是一個問題,你就能夠做到

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

你可以做到這一點一個簡單的擴展方法:

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

當通過一個動作可能是有用的,它並不像枚舉在樹結構中的所有項目的迭代器一樣靈活,使他們可用於其他LINQ運營商:

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 
// e.g., "Parent > Child > Grandchild": 

TreeNode node = myTreeView.SelectedNode; 

var text = node.Walk(n => n.Parent).Select(n => n.Text); 

string breadcrumbText = string.Join(" > ", text.Reverse());