Запускает ли “Выбрать новый” в linq оценку / загрузку?

StackOverflow https://stackoverflow.com/questions/810879

Вопрос

В настоящее время я пытаюсь создать класс, который реализует 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
    };
}
Это было полезно?

Решение

НЕТ, 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);
    }
}

Ключевым моментом здесь является то, что он оценивает lazy - не все сразу.

Любой подход должен быть сопоставимым - разница лишь в том, что без yield return, некоторые код будет запущен немедленно - но только код для создания .Where(...).Select(...) цепочка - на самом деле она не будет обрабатывать строки, пока вы не начнете повторять результат.

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top