5

Is it possible to use yield inline at the ForEach method?

private static IEnumerable<string> DoStuff(string Input)
{
    List<string> sResult = GetData(Input);
    sResult.ForEach(x => DoStuff(x));

    //does not work
    sResult.ForEach(item => yield return item;); 

    //does work
    foreach(string item in sResult) yield return item;
}

if not, is there a reason why it doesn't work?

fubo
  • 44,811
  • 17
  • 103
  • 137
  • 1
    have a look at: http://stackoverflow.com/q/1217729/1859022 – user1859022 Mar 09 '16 at 16:00
  • 4
    First, *Why* use this syntax instead of `.Select(x=>DoStuff(x))` ? Second, `ForEach` doesn't return a result, so trying to return something with `return` or `yield` is invalid – Panagiotis Kanavos Mar 09 '16 at 16:02
  • @PanagiotisKanavos `Select` doesn't work combined with a recursive approach – fubo Mar 09 '16 at 16:03
  • @fubo actually, you can find ways to make it work. You'll find many examples that show how eg to walk trees with LINQ. At the very least you can use `.Concat` to combine recursion results befor returning the result from select. Trying to use a `yield` inside an Action is simply invalid though. – Panagiotis Kanavos Mar 09 '16 at 16:06
  • 1
    It looks like what you want to do is something like `foreach(var item in GetData(Input)) { foreach(var sub in DoStuff(item)){ yield return sub; } yield return item;}` Or you might want to yield the `item` before the `sub` items. – juharr Mar 09 '16 at 16:14
  • Without even going into deep detail which answered here already, you're trying to compare `ForEach` method vs `foreach` flow control keyword. And as it is pointed above you can't return anything from `ForEach`. – T.S. Mar 10 '16 at 01:31

2 Answers2

9

No, List<T>.ForEach can't be used for this.

List<T>.ForEach takes an Action<T> delegate.

Action<T> "Encapsulates a method that has a single parameter and does not return a value."

So the lambda you've created can't return anything if it's to "fit" in an Action<T>.

7

Because as you can see here a lambda function is compiled to a separate method:

This:

x => DoStuff(x)

is converted to

internal void <DoStuff>b__1_0(string x)
{
    C.DoStuff(x);
}

This separate method isn't a IEnumerable<> so it clearly can't support the yield keyword.

So for example this:

item => yield return item;

would be converted to:

internal void <DoStuff>b__1_0(string item)
{
    yield return item;
}

that has the yield but isn't IEnumerable<string>.

xanatos
  • 109,618
  • 12
  • 197
  • 280