Frage

Ich versuche zur Zeit eine Klasse zu erstellen, die IEnumerable<T> um implementiert eine Hierarchie aus einer flachen Liste von Objekten zu konstruieren, die Verweise auf miteinander über eine ParentId Eigenschaft. Ich möchte eine fließend-Schnittstelle für diese schreiben, so dass ich etwas tun kann,

IEnumerable<Tab> tabs = GetTabs();

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

Also, um die Ausbeute Aussage, frage ich mich, ob ich so etwas wie dies in meiner NodeHierarchy : IEnumerable<TabNode> Klasse tun konnte:

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

oder ob ich hätte so etwas tun:

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
    };
}
War es hilfreich?

Lösung

Nein, select new nicht Auswertung auslösen. Dies wird zu einem Aufruf der Karte an:

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

Und beachten Sie, dass Select (für LINQ-to-Objects, zumindest) ist im Wesentlichen so etwas wie:

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

Der entscheidende Punkt hier ist, dass es faul auswertet - nicht alle auf einmal

.

Beide Ansätze sollten vergleichbar sein - der einzige Unterschied ist, dass ohne yield return, einige Code sofort ausgeführt werden - aber nur der Code die .Where(...).Select(...) Kette zu bauen - es wird nicht wirklich die Zeilen, bis Sie verarbeiten starten Sie das Ergebnis iterieren.

Darüber hinaus abhängig von der Datenquelle, kann dieser Ansatz tatsächlich effizienter sein - z. B. mit einem LINQ-to-SQL-Backend, da der TSQL Generator der nicht benötigten Spalten überspringt

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top