2009-05-01 25 views
1

我目前正在尝试创建一个实现IEnumerable<T>的类,以便从通过ParentId属性相互引用的对象的平面列表构造一个Hierarchy。我想为此编写一个流畅的接口,所以我可以做这样的事情linq中的“Select New”是否触发评估/加载?

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

您可以使用空格而不是制表符重新格式化您的代码吗?目前相当难以理解。 – 2009-05-01 10:18:45

回答

2

不,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(...).Select(...)链 - 它不会实际处理行,直到你开始迭代结果。因为TSQL生成器可以跳过不必要的列,所以根据数据源,该方法实际上可以更高效 - 例如,使用LINQ-to-SQL后端。