代码之家  ›  专栏  ›  技术社区  ›  Jon Norton

比.ToArray()更好的方法来强制LINQ输出的枚举

  •  13
  • Jon Norton  · 技术社区  · 17 年前

    我正在使用LINQ to对象,并且有一个函数,在某些情况下,我需要在调用之前修改基础集合 Aggregate(...) 然后在函数返回结果之前将其返回到原始状态 聚合(…) . 我当前的代码如下所示:

    bool collectionModified = false;
    if(collectionNeedsModification)
    {
        modifyCollection();
        collectionModified = true;
    }
    
    var aggregationResult = from a in
                                (from b in collection
                                 where b.SatisfysCondition)
                                 .Aggregate(aggregationFunction)
                            select a.NeededValue;
    
    if(collectionModified)
        modifyCollection();
    
    return aggregationResult;
    

    但是,如前所述,如果修改集合,我将得到错误的结果,因为我将集合恢复到以前的原始状态 aggregationResult 枚举,并计算LINQ结果。我目前的解决方案是使用 .ToArray() 在我的LINQ查询中,如下所示:

    var aggregationResult = (from a in
                                (from b in collection
                                 where b.SatisfysCondition)
                                 .Aggregate(aggregationFunction)
                             select a.NeededValue).ToArray();
    

    结果数组的大小总是很小(<100个项目),因此内存/处理时间不成问题。这是处理我的问题的最佳方法,还是有更好的方法强制计算LINQ查询?

    4 回复  |  直到 17 年前
        1
  •  15
  •   Jon Skeet    9 年前

    副作用通常是个坏主意,因为用这种逻辑很难理解。话虽如此,执行此操作并强制进行完整评估的最简单方法可能是迭代:

    foreach (var result in aggregationResult)
    {
        // Deliberately empty; simply forcing evaluation of the sequence.
    }
    

    LastOrDefault() 避免ToArray()中涉及的所有复制。 Count() IList<T> (这需要一条捷径)。

        2
  •  13
  •   Markus Johnsson    15 年前

    (注意:键入时手头没有编译器,因此代码未经测试)

    如果已将.NET的被动扩展作为依赖项,则可以使用Run():

    aggregationResult.Run();
    

    但可能不值得为此添加依赖项。

    public static MyLinqExtensions 
    {
         public static void Run<T>(this IEnumerable<T> e)
         {
             foreach (var _ in e);
         }
    }
    
        3
  •  3
  •   Aleris    17 年前

    最好避免像上面modifyCollection这样的副作用函数。

    更好的方法是创建一个返回修改后的集合(或查询)的函数,让初始集合保持原样。

    var modifiedCollection = ModifyCollection(collection, collectionNeedsModification);
    
    var aggregationResult = from a in
                            (from b in modifiedCollection
                             where b.SatisfysCondition)
                             .Aggregate(aggregationFunction)
                        select a.NeededValue;
    

        4
  •  0
  •   Mehrdad Afshari    17 年前

    如果您总是使用结果,我认为您的方法不会有问题(因为您的结果集不大,所以不会消耗太多内存。顺便说一下,如果您这样做而从不使用结果,那么会造成性能损失)。 所以,是的,这是正确的方法。