Linq Concat可以延迟加载它的内容

时间:2019-01-11 03:29:13

标签: c# linq

我有以下Linq

var seq = 
         GetCollectionA()
          .Concat(GetCollectionB())
          .Concat(GetCollectionC())
          .FirstOrDefault();

如果GetCollectionA()返回了一些对象,则包裹在Concat中的其他两个方法将仍然运行,并且一无所获。这些方法中的每一个都返回一个实际的数组,而不是真正的Linq友好的Enumerable。我的目标是在实际需要时对Concat进行参数评估。如果Concat允许像这样延迟加载lambda表达式,那会不会很好?

var seq = 
         GetCollectionA()
          .Concat(() => GetCollectionB())
          .Concat(() => GetCollectionC())
          .FirstOrDefault();

我正在考虑以下解决方法,如果在第一个集合中找到该元素,此方法是否可以工作,并且不调用后续的集合方法?

var seq = 
         GetCollectionA()
          .Concat(Enumerable.Range(1, 1).SelectMany(_ => GetCollectionB()))
          .Concat(Enumerable.Range(1, 1).SelectMany(_ => GetCollectionC()))
          .FirstOrDefault();

Concat是否会实际上对序列进行迭代,而不是将其放入迭代管道中?

有更好的方法吗?

2 个答案:

答案 0 :(得分:1)

考虑使用这种方法一次枚举一个集合:

关键是#include "multiboot.h" typedef int (*initcall_t)(void); #define __section(S) __attribute__((__section__(#S))) #define __used __attribute__((__used__)) #define __init __section(.init.text) static int __init myFunc(void) { for (int i = 0; i < 3; i++) ; return 0; } void kernel_main(multiboot_info_t *mbd, unsigned int magic) { magic = magic; mbd = mbd; while (1) ; } static __used initcall_t __initcall_myFunc6 __section(".initcall6.init") = myFunc; 接受SmartConcat,而不是方法调用(当前正在使用)的结果。因此,一旦找到匹配项,它就可以停止执行。

Func

或者,如果要处理引用类型,请考虑:

using System;
using System.Collections.Generic;
using System.Linq;

namespace Test
{
    static class ExtraLINQ
    {
        public static IEnumerable<T> SmartConcat<T>(this IEnumerable<T> source, params Func<IEnumerable<T>>[] extras)
        {
            foreach (var entry in source)
                yield return entry;


            foreach (var laterEntries in extras)
            {
                foreach (var laterEntry in laterEntries())
                {
                    yield return laterEntry;
                }
            }
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            // Executes both functions
            var first = GetCollectionA().Concat(GetCollectionB()).FirstOrDefault();
            Console.WriteLine(first);

            // Executes only the first
            var otherFirst = GetCollectionA().SmartConcat(GetCollectionB).FirstOrDefault();
            Console.WriteLine(otherFirst);

            Console.ReadLine();
        }

        private static IEnumerable<int> GetCollectionA()
        {
            var results = new int[] { 1, 2, 3 };
            Console.WriteLine("GetBob");
            return results;
        }

        private static IEnumerable<int> GetCollectionB()
        {
            var results = new int[] { 4,5,6 };
            Console.WriteLine("GetBob4");
            return results;
        }

    }
}

答案 1 :(得分:-1)

显然我的丑陋骇客作品有用。

    public static void Main()
    {
        Console.WriteLine("Hello World");
        var seq = GetNumbers().Concat(Enumerable.Range(1, 1).SelectMany(_ => GetNumbers())).FirstOrDefault();
        Console.WriteLine(seq);
    }

    static int[] GetNumbers()
    {
        Console.WriteLine("GetNumbers called");
        return new[]{1, 2, 3};
    }
}

GetNumbers只被叫过一次

Hello World
GetNumbers called
1

这是小提琴 https://dotnetfiddle.net/VDlL79