6

C# doesn't allow lambda functions to represent iterator blocks (e.g., no "yield return" allowed inside a lambda function). If I wanted to create a lazy enumerable that yielded all the drives at the time of enumeration for example, I'd like to do something like

IEnumerable<DriveInfo> drives = {foreach (var drive in DriveInfo.GetDrives()) 
                                     yield return drive;};

It took a while, but I figured out this as a way to get that functionality:

var drives = Enumerable.Range(0, 1).SelectMany(_ => DriveInfo.GetDrives());

Is there a more idiomatic way?

Dax Fohl
  • 10,654
  • 6
  • 46
  • 90

2 Answers2

1
 var drives = new Func<IEnumerable<DriveInfo>>(DriveInfo.GetDrives);

 foreach(var drive in drives())
     Console.WriteLine(drive);

This solution has an important feature; It recognizes that multiple enumeration can be potentially bad. For instance, the underlying enumerator might make snap-shot of the list and then only ever enumerate over than list. There have been other discussions on multiple-enumerators See Answers here and here

Community
  • 1
  • 1
Meirion Hughes
  • 24,994
  • 12
  • 71
  • 122
1

Why not write your own method, something like:

public static IEnumerable<T> GetLazily<T>(Func<IEnumerable<T>> getSource)
{
  foreach (var t in getSource())
    yield return t;
}

or:

public static IEnumerable<T> GetLazily<T>(Func<IEnumerable<T>> getSource)
{
  return (new int[1]).SelectMany(_ => getSource());
}

It ought to allow usage like this:

var drives = GetLazily(DriveInfo.GetDrives);
Jeppe Stig Nielsen
  • 60,409
  • 11
  • 110
  • 181