1

私は現在IEnumerable<T>、ParentIdプロパティを介して相互に参照するオブジェクトのフラットリストから階層を構築するために実装するクラスを作成しようとしています。このための流暢なインターフェースを書きたいので、このようなことができます

IEnumerable<Tab> tabs = GetTabs();

IEnumerable<TabNode> tabNodes = tabs.AsHierarchy().WithStartLevel(2).WithMaxDepth(5);

NodeHierarchy : IEnumerable<TabNode>それで、yieldステートメントについて、クラス内でこのようなことができるかどうか疑問に思います。

private IEnumerable<TabNode> _nodes;

public NodeHierarchy(IEnumerable<Tab> tabs)
{
    _nodes = CreateHierarchy(tabs);
}

public IEnumerable<TabNode> CreateHierarchy(IEnumerable<Tab> tabs)
{
    /* About this block: I'm trying to find the top level 
    nodes of the first tab collection, maybe this is done poorly? */
    var tabIds = tabs.Select(t => t.TabID);
    IEnumerable<TabNode> nodes = from tab in tabs
                             where !tabIds.Contains(tab.ParentId)
                                 select new TabNode {
                                            Tab = node,
                                            ChildNodes = CreateHierarchy(tabs, node.TabID, 1),
                                            Depth = 1 };
    return nodes;
}

または私がこのようなことをしなければならないかどうか:

private IEnumerable<TabNode> _nodes;

public NodeHierarchy(IEnumerable<Tab> tabs)
{
    _nodes = CreateHierarchy(tabs);
}

public IEnumerable<TabNode> CreateHierarchy(IEnumerable<Tab> tabs)
{
var tabIds = tabs.Select(t => t.TabID);
IEnumerable<Tab> startingNodes = from tab in tabs
                                 where !tabIds.Contains(tab.ParentId)
                                 select tab;

foreach(Tab node in startingNodes)
{
    yield return
    new TabNode()
        {
        Tab = node,
        ChildNodes = CreateHierarchy(tabs, node.TabID, 1),
        Depth = 1
    };
}
4

1 に答える 1

2

いいえ、select new評価はトリガーされません。これは、次の呼び出しにマップされます。

 .Select(tab => new TabNode {...})

Selectまた、 (少なくともLINQ-to-Objectsの場合)基本的に次のようなものであることに注意してください。

public static IEnumerable<TDest> Select<TSource,TDest>(
    this IEnumerable<TSource> source,
    Func<TSource,TDest> selector)
{
    foreach(TSource item in source)
    {
        yield return selector(source);
    }
}

ここで重要なのは、それが怠惰なものを評価するということです-一度にすべてではありません。

どちらのアプローチも同等である必要があります。唯一の違いは、がないyield returnと、一部のコードがすぐに実行されることですが、.Where(...).Select(...)チェーンを構築するためのコードのみです。結果の反復を開始するまで、実際には行を処理しません。

さらに、データソースによっては、TSQLジェネレーターが不要な列をスキップできるため、このアプローチは実際にはより効率的である可能性があります。たとえば、LINQ-to-SQLバックエンドを使用します。

于 2009-05-01T11:00:24.783 に答える