是“选择新”在linq中触发评估/加载?
-
03-07-2019 - |
题
我目前正在尝试创建一个实现 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生成器可以跳过不必要的列。
不隶属于 StackOverflow