遍历列表,执行方法:可以扩展吗?

发布于 2024-09-11 03:07:09 字数 434 浏览 3 评论 0原文

我有一个像这样的数据结构

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

或者这是不可能的,我必须在我的业务逻辑中创建一个特殊的方法?

多谢。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

一页 2024-09-18 03:07:09

您的意思是 IEnumerable 上的扩展方法吗?这当然是可行的:

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

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);
世界如花海般美丽 2024-09-18 03:07:09

我假设您的主类应该是 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);
        }
    }
}

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);
        }
    }
}
绝不服输 2024-09-18 03:07:09

我不确定你的参数应该表示什么,但如果第二个参数是谓词,你可能想要做这样的事情:

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

我也可能会抛出这样的函数,在 ListList< T>,所以if ToList 不是问题,您可以这样做

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

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);
橘和柠 2024-09-18 03:07:09

您可以使用简单的扩展方法来做到这一点:

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

public static partial class IEnumerableExtensions
{
    /// <summary>
    /// Executes an <see cref="Action<T>"/> 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<T>"/> in which each item should be processed.</param>
    /// <param name="action">The <see cref="Action<T>"/> 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);
    }
}

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<T>"/> 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<T>"/> in which each item should be processed.</param>
    /// <param name="action">The <see cref="Action<T>"/> 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);
    }
}
深爱不及久伴 2024-09-18 03:07:09

虽然传递 Action 可能很有用,但它不如枚举树结构中所有项目的迭代器灵活,从而使它们可与其他 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() );

While passing an Action might be useful, it isn't as flexible as an iterator that enumerates all items in a 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
// 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() );
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文