Pregunta

Actualmente estoy tratando de crear una clase que implemente IEnumerable < T > para construir una Jerarquía a partir de una lista plana de objetos que tienen referencias entre sí a través de una propiedad ParentId. Me gustaría escribir una interfaz fluida para esto, así puedo hacer algo como esto

IEnumerable<Tab> tabs = GetTabs();

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

Entonces, sobre la declaración de rendimiento, me pregunto si podría hacer algo como esto dentro de mi NodeHierarchy: IEnumerable < TabNode > class:

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 si tendría que hacer algo como esto:

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
    };
}
¿Fue útil?

Solución

No, seleccionar nuevo no activará la evaluación. Esto se asignará a una llamada a:

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

Y tenga en cuenta que Select (para LINQ-to-Objects, al menos) es esencialmente algo como:

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

El punto clave aquí es que evalúa la pereza, no todas a la vez.

Cualquiera de los dos enfoques debería ser comparable: la única diferencia es que sin return return , some se ejecutará inmediatamente, pero solo el código para construir el . (...). Seleccione (...) cadena: en realidad no procesará las filas hasta que comience a iterar el resultado.

Además, dependiendo de la fuente de datos, ese enfoque puede ser más eficiente, por ejemplo, con un backend LINQ-to-SQL, ya que el generador TSQL puede omitir las columnas innecesarias.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top