A function's result is the source for a LINQ query. I want it to be evaluated lazily, every time I use the query, not be locked when I create it. This is an example of what I mean:
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()
runs only once - when query
is created, even without calling a terminating method on it like ToList()
. What I would want is for Console.WriteLine()
(or any other function in its place) to be executed only when I use the query with ToList()
or Count()
etc.
If you don't mind a bit of extra infrastructure, it's not too bad - you can create a DeferredEnumerable<T>
class that just executes the given delegate every time it's asked for an iterator. A static non-generic class can then help with type inference. Complete example:
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));
}
}
See more on this question at Stackoverflow