3

クラスがあると仮定します

public class RMenuItem
{
    public List<RMenuItem> ChildrenItems { get; }
    public decimal OperationID { get; }
    public string Name { get; }
}

ご覧のとおり、通常のように、各メニュー項目に子項目を含めることができます。私の仕事は、このリストの各項目を繰り返し処理し、何らかのアクションを適用することです。古典的な決定は、再帰的な繰り返しを書くことです。しかし、LINQ が私のタスクをより簡単にすることができるかどうかは興味深いですか? たとえば、オブジェクトのフラット リストを取得できるクエリを記述でき、これを foreach で簡単に反復できるとします。しかし、この方法での私の試みはまだ成功していません。だからどんな助けでも大歓迎です!

4

4 に答える 4

4

可能です:

    public void PrintAllNames(RMenuItem rootItem)
    {
        Action<RMenuItem> print = null;
        print = m =>
            {
                Console.WriteLine(m.Name);
                m.ChildrenItems.ForEach(print);
            };
        print(rootItem);
    }

それ自体を使用できるprintように宣言する必要があることに注意してください。printこれは、私がむしろ使用したい再帰的方法に直接匹敵します:

    public void PrintAllNames(RMenuItem rootItem)
    {
        Console.WriteLine(rootItem.Name);
        rootItem.ChildrenItems.ForEach(PrintAllNames);
    }

(ただし、より複雑な状況では、機能的なソリューションが最も理にかなっているかもしれません)

于 2009-12-23T09:52:22.833 に答える
1

このように、クラスで(または必要に応じて拡張として) Flatten メソッドを定義できます

public IEnumerable<RMenuItem> Flatten()
{
    foreach (var item in ChildrenItems)
    {
        yield return item;
    }
    return ChildrenItems.SelectMany(item => item.Flatten());
}

次に、各要素で何かを行うのは次のように簡単です

RMenuItem rootItem ;

    // do somthing with the root item
    foreach (var item  in rootItem.Flatten())
    {
        // do somthing
    }
于 2009-12-23T16:34:54.377 に答える
1

実際、LINQを使用してそれを行うことができSelectMany、リストを平らにします。ほんの一例です

menuItemsList.SelectMany(x => x.ChildrenItems).Where(c => c.someChildProperty);

ありがとう

編集:

コメントに応えて、SelectMany以前の例を挙げただけです。ご指摘ありがとうございます。

menuItemsList.SelectMany(x => x.ChildrenItems.Select(p => p)).Where(c => c.someChildProperty);

またはこのようなもの

menuItemsList.SelectMany(x => x.ChildrenItems).Select(p => p).Where(c => c.someChildProperty);

編集2

ああ..今、私はあなたが何を望んでいるのか理解しました..

上記のクエリを少し変更して、必要なことを行うことができます

menuItemsList
.SelectMany(x => { //do something with x like printing it  
                    x.ChildrenItems 
                 })
.Select(p => { // do something with p like printing it 
                  p 
             });

基本的に、要素内で必要なことを行うことができます{}

ありがとう

于 2009-12-23T09:58:22.033 に答える
1

これを達成するための2つの方法を提案します。クラスを変更することを意味しますが、ユーティリティ メソッドを使用してすべてのアイテムを取得するか、Visitor パターンを実装することができます。RMenuItem

ユーティリティ方法:

    static IEnumerable<RMenuItem> GetAllMenuItems(IList<RMenuItem> items)
    {
        if (items == null)
            throw new ArgumentNullException("items");

        Queue<RMenuItem> queue = new Queue<RMenuItem>(items);

        while (queue.Count > 0)
        {
            var item = queue.Dequeue();
            if (item.ChildrenItems != null)
            {
                foreach (var child in item.ChildrenItems)
                {
                    queue.Enqueue(child);
                }
            }
            yield return item;
        }
    }

イテレータブロックを使用できるため、再帰よりも命令的な方法を好みます。

訪問者パターン:

    public interface IRMenuItemVisitor
    {
        void Visit(RMenuItem item);
    }

    public class PrintRMenuItemVisitor : IRMenuItemVisitor
    {
        public void Visit(RMenuItem item)
        {
            Console.WriteLine(item);
        }
    }

    public interface IRMenuItem
    {
        void Accept(IRMenuItemVisitor visitor);
    }

    public class RMenuItem : IRMenuItem
    {
        // ...

        public void Accept(IRMenuItemVisitor visitor)
        {
            visitor.Visit(this);
            if (ChildrenItems != null)
            {
                foreach (var item in ChildrenItems)
                {
                    item.Accept(visitor);
                }
            }
        }
    }

使用法:

        RMenuItem m1 = new RMenuItem
        {
            Name = "M1",
            ChildrenItems = new List<RMenuItem> { 
                new RMenuItem { Name = "M11" }, 
                new RMenuItem { 
                    Name = "M12", 
                    ChildrenItems = new List<RMenuItem> {
                        new RMenuItem { Name = "M121" },
                        new RMenuItem { Name = "M122" }
                    }
                } 
            }
        };

        RMenuItem m2 = new RMenuItem
        {
            Name = "M2",
            ChildrenItems = new List<RMenuItem> { 
                new RMenuItem { Name = "M21" }, 
                new RMenuItem { Name = "M22" }, 
                new RMenuItem { Name = "M23" } 
            }
        };

        IList<RMenuItem> menus = new List<RMenuItem> { m1, m2 };
        foreach (var menu in GetAllMenuItems(menus))
        {
            Console.WriteLine(menu);
        }

        // or

        IList<RMenuItem> menus = new List<RMenuItem> { m1, m2 };
        foreach (var menu in menus)
        {
            menu.Accept(new PrintRMenuItemVisitor());
        }
于 2009-12-23T09:59:02.117 に答える