代码之家  ›  专栏  ›  技术社区  ›  Jakub Dąbek

LINQ将函数的结果作为源延迟执行(例如,Console.ReadLine)

  •  2
  • Jakub Dąbek  · 技术社区  · 8 年前

    LINQ查询 。我希望每次使用查询时都能缓慢地对其进行评估,而不是在创建查询时将其锁定。这是我的意思的一个例子:

    var query = from c in Console.ReadLine()
                group c by char.IsDigit(c) into gr
                select new { IsDigit = gr.Key, Count = gr.Count() };
    

    Console.WriteLine() query ToList() .我想要的是 控制台.WriteLine() ToList() Count()

    3 回复  |  直到 8 年前
        1
  •  4
  •   Jon Skeet    8 年前

    如果你不介意一些额外的基础设施,那也不错——你可以创建一个 DeferredEnumerable<T>

    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Linq;
    
    // Just for type inference...
    public static class DeferredEnumerable
    {
        public static IEnumerable<T> For<T>(Func<IEnumerable<T>> func) =>
            new DeferredEnumerable<T>(func);
    }
    
    public sealed class DeferredEnumerable<T> : IEnumerable<T>
    {
        private readonly Func<IEnumerable<T>> func;
    
        public DeferredEnumerable(Func<IEnumerable<T>> func)
        {
            this.func = func;
        }
    
        public IEnumerator<T> GetEnumerator() => func().GetEnumerator();
    
        IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
    }
    
    class Test
    {
        static void Main()
        {
            var query = 
                from c in DeferredEnumerable.For(Console.ReadLine)
                group c by char.IsDigit(c) into gr
                select new { IsDigit = gr.Key, Count = gr.Count() };
    
    
            Console.WriteLine("First go round");
            Console.WriteLine(string.Join(Environment.NewLine, query));
    
            Console.WriteLine("Second go round");
            Console.WriteLine(string.Join(Environment.NewLine, query));
        }
    }
    
        2
  •  0
  •   Jakub Dąbek    8 年前

    我找到了两种解决方案,但它们真的很难看,我不想使用它们


    解决方案1

    static IEnumerable<string> GetDeferredConsoleReadLine()
    {
        yield return Console.ReadLine();
    }
    
    var query = from line in GetDeferredConsoleReadLine()
                from c in line
                group c by char.IsDigit(c) into gr
                select new { IsDigit = gr.Key, Count = gr.Count() };
    

    yield return 函数的结果。


    var query = from line in
                    from _ in "1"
                    select Console.ReadLine()
                from c in line
                group c by char.IsDigit(c) into gr
                select new { IsDigit = gr.Key, Count = gr.Count() };
    

    有没有其他方法可以做到这一点 SelectMany 在查询中?

        3
  •  0
  •   tmaj    8 年前

    您可以将查询放在一个单独的方法中。

    static void Main(string[] args)
    {
        while (true)
        {
            foreach (var y in RunQuery()) {
                Console.WriteLine($"{y.IsDigit}: {y.Count}");
            }
        }
    }
    
    class A{public bool IsDigit { get; set; } public int Count { get; set; } }
    
    private static IEnumerable<A> RunQuery()
    {
        return from c in Console.ReadLine()
                    group c by char.IsDigit(c) into gr
                    select new A { IsDigit = gr.Key, Count = gr.Count() };
    }