C# linq中的“选择新”是否触发评估/加载?

C# linq中的“选择新”是否触发评估/加载?,c#,linq,ienumerable,yield,fluent-interface,C#,Linq,Ienumerable,Yield,Fluent Interface,我目前正在尝试创建一个实现IEnumerable的类,以便从对象的平面列表中构造层次结构,这些对象通过ParentId属性相互引用。我想为此编写一个流畅的界面,这样我就可以这样做了 IEnumerable<Tab> tabs = GetTabs(); IEnumerable<TabNode> tabNodes = tabs.AsHierarchy().WithStartLevel(2).WithMaxDepth(5); 所以,关于收益率声明,我想知道我是否可以在我的节

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

IEnumerable<Tab> tabs = GetTabs();

IEnumerable<TabNode> tabNodes = tabs.AsHierarchy().WithStartLevel(2).WithMaxDepth(5);
所以,关于收益率声明,我想知道我是否可以在我的节点层次结构中做这样的事情:IEnumerable类:

或者我是否必须这样做:

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(tab => new TabNode {...})
请注意,对于LINQ to对象,Select至少本质上类似于:

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,而不是一次评估所有

这两种方法都应该是可比较的-唯一的区别是,如果没有收益率回报,一些代码将立即运行-但只有用于构建的代码。其中…选择。。。链-在您开始迭代结果之前,它不会实际处理行


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

您能使用空格而不是制表符重新格式化代码吗?现在很难读。是的,我知道,谢谢,我正在写。。。复制粘贴作业在此处实际上不起作用:
public static IEnumerable<TDest> Select<TSource,TDest>(
    this IEnumerable<TSource> source,
    Func<TSource,TDest> selector)
{
    foreach(TSource item in source)
    {
        yield return selector(source);
    }
}