我目前正在尝试创建一个实现 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
    };
}
有帮助吗?

解决方案

不, select new 不会触发评估。这将映射到对:

的调用
 .Select(tab => new TabNode {...})

请注意 Select (至少对于LINQ到对象)基本上是这样的:

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 (...)。选择(...)链 - 在开始迭代结果之前,它不会实际处理行。

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

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top