Domanda

Attualmente sto cercando di creare una classe che implementa IEnumerable < T > per costruire una Gerarchia da un elenco semplice di oggetti che hanno riferimenti reciproci attraverso una proprietà ParentId. Mi piacerebbe scrivere un'interfaccia fluida per questo in modo da poter fare qualcosa del genere

IEnumerable<Tab> tabs = GetTabs();

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

Quindi, riguardo alla dichiarazione di rendimento, mi chiedo se potrei fare qualcosa del genere all'interno della mia classe NodeHierarchy: IEnumerable < TabNode > :

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

o se dovrei fare qualcosa del genere:

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
    };
}
È stato utile?

Soluzione

No, seleziona nuovo non attiverà la valutazione. Questo verrà associato a una chiamata a:

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

E nota che Select (almeno per LINQ-to-Objects) è essenzialmente simile a:

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

Il punto chiave qui è che valuta pigro - non tutto in una volta.

Entrambi gli approcci dovrebbero essere comparabili - l'unica differenza è che senza rendimento> , il codice un po ' verrà eseguito immediatamente - ma solo il codice per creare il . (...). Seleziona la catena (...) : in realtà non elaborerà le righe fino a quando non inizierai a ripetere il risultato.

Inoltre, a seconda dell'origine dati, tale approccio può effettivamente essere più efficiente, ad esempio con un backend LINQ-to-SQL, poiché il generatore TSQL può saltare le colonne non necessarie.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top