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

发布于 2024-07-19 06:11:24 字数 1861 浏览 11 评论 0原文

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

IEnumerable<Tab> tabs = GetTabs();

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

所以,关于yield语句,我想知道我是否可以在我的NodeHierarchy:IEnumerable类中做这样的事情:

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

I'm currently trying to create a class which implements IEnumerable<T> in order to construct a Hierarchy from a flat list of objects which have references to each other through a ParentId property. I'd like to write a fluent interface for this so I can do something like this

IEnumerable<Tab> tabs = GetTabs();

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

So, about the yield statement, I wonder whether I could do something like this within my NodeHierarchy : IEnumerable<TabNode> class:

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

or whether I would have to do something like this:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

情绪 2024-07-26 06:11:24

不,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 生成器可以跳过不必要的列。

No, select new will not trigger evaluation. This will map to a call to:

 .Select(tab => new TabNode {...})

And note that Select (for LINQ-to-Objects, at least) is essentially something like:

public static IEnumerable<TDest> Select<TSource,TDest>(
    this IEnumerable<TSource> source,
    Func<TSource,TDest> selector)
{
    foreach(TSource item in source)
    {
        yield return selector(source);
    }
}

The key point here being that it evaluates lazy - not all at once.

Either approach should be comparable - the only difference is that without yield return, some code will run immediately - but only the code to build the .Where(...).Select(...) chain - it won't actually process the rows until you start iterating the result.

Furthermore, depending on the data source, that approach can actually be more efficient - for example, with a LINQ-to-SQL backend, as the TSQL generator can skip the unnecessary columns.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文