函数的结果是 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()
那样调用终止方法。我想要的是Console.WriteLine()
(或其他任何功能)仅在我使用ToList()
或Count()
等查询时执行。
答案 0 :(得分:4)
如果你不介意一些额外的基础设施,那也不是太糟糕 - 你可以创建一个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));
}
}
答案 1 :(得分:0)
我找到了2个解决方案,但它们真的很难看,我不想使用它们
解决方案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() };
这使用延迟执行函数结果的可枚举函数{{1}。
解决方案2
这在另一个内部使用LINQ查询的另一个笨重的构造,它返回一个元素(事情是它需要一个源 - 我使用一个元素字符串并丢弃结果,但这不是很干净)< / p>
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() };
?
答案 2 :(得分:0)
您可以将查询放在单独的方法中。
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() };
}