【问题标题】:Does "Select New" in linq trigger an evaluation / load?linq 中的“选择新”是否会触发评估/加载?
【发布时间】:2010-10-23 02:11:31
【问题描述】:

我目前正在尝试创建一个实现IEnumerable<T> 的类,以便从通过 ParentId 属性相互引用的对象的平面列表构造层次结构。我想为此编写一个流畅的界面,以便我可以做这样的事情

IEnumerable<Tab> tabs = GetTabs();

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

所以,关于 yield 声明,我想知道我是否可以在我的 NodeHierarchy : IEnumerable&lt;TabNode&gt; 类中做这样的事情:

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

【问题讨论】:

  • 你能用空格而不是制表符重新格式化你的代码吗?目前它非常难以阅读。
  • 是的,我知道,谢谢,我正在努力...复制粘贴工作在这里并没有真正起作用:)

标签: c# linq ienumerable yield fluent-interface


【解决方案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);
    }
}

这里的关键是它评估惰性 - 不是一次全部。

这两种方法都应该具有可比性 - 唯一的区别是,如果没有 yield return,一些 代码将立即运行 - 但只有构建 .Where(...).Select(...) 链的代码 - 它实际上不会处理行,直到您开始迭代结果。

此外,根据数据源,这种方法实际上可能更有效 - 例如,使用 LINQ-to-SQL 后端,因为 TSQL 生成器可以跳过不必要的列。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-10-14
    • 2017-09-25
    • 2012-02-03
    • 1970-01-01
    • 1970-01-01
    • 2022-01-13
    • 1970-01-01
    相关资源
    最近更新 更多