«Выбрать новый» в linq вызывает оценку / загрузку? - PullRequest
1 голос
/ 01 мая 2009

В настоящее время я пытаюсь создать класс, который реализует IEnumerable<T>, чтобы построить иерархию из плоского списка объектов, которые имеют ссылки друг на друга через свойство ParentId. Я хотел бы написать свободный интерфейс для этого, чтобы я мог сделать что-то вроде этого

IEnumerable<Tab> tabs = GetTabs();

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

Итак, что касается выражения yield, мне интересно, смогу ли я сделать что-то подобное в моем классе 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;
}

или я должен был бы сделать что-то вроде этого:

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

1 Ответ

2 голосов
/ 01 мая 2009

Нет, 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(...) - он фактически не будет обрабатывать строк, пока вы не начнете повторять результат.

Кроме того, в зависимости от источника данных этот подход может быть более эффективным - например, с бэкэндом LINQ-to-SQL, поскольку генератор TSQL может пропускать ненужные столбцы.

...