4

I have defined the following extension method:

public static void ForEach<T>(this IEnumerable<T> sequence, Action<T> action)
{
   foreach (T obj in sequence)
   { 
      action(obj); 
   } 
}

I can then use it as:

new [] {1, 2, 3} // an IEnumerable<T>
.ForEach(n => 
{
  // do something 
});

I want to be able to take advantage of continue and break inside my extension method so that I can do:

new [] {1, 2, 3}
.ForEach(n => 
{
    // this is an overly simplified example
    // the n==1 can be any conditional statement
    // I know in this case I could have just used .Where
    if(n == 1) { continue; }
    if(n == -1) { break; }      
    // do something 
});

Can these keywords only be used within a for, foreach, while or do-while loops?

MaYaN
  • 6,683
  • 12
  • 57
  • 109
  • 3
    IMHO, this extension method makes no sense at all. It just complicates your code. Why not use the `foreach` loop? You don't have to replace everything with an extension method. – Daniel Hilgarth Jul 16 '15 at 13:04
  • @Daniel - I would have to disagree, I am a big fan of functional programming `linq` and `morelinq` and in my opinion (and the opinion of many others in my team) this is much easier to read than the alternative. – MaYaN Jul 16 '15 at 13:06
  • 1
    For each is already on list fyi – Brandon Seydel Jul 16 '15 at 13:11
  • but not on IEnumerable ;-) hence why it is available in `MoreLinq` – MaYaN Jul 16 '15 at 13:26

3 Answers3

7

Can these keywords only be used within a for, foreach, while loops?

Yes. Those statements are limited to loop types. As the docs say:

The continue statement passes control to the next iteration of the enclosing while, do, for, or foreach statement in which it appears.

And:

The break statement terminates the closest enclosing loop or switch statement in which it appears. Control is passed to the statement that follows the terminated statement, if any.

I'd recommend you use a regular foreach, which is self expressive as is. I think any attempt to use them semantically inside your ForEach extension method will result in weirder code than using a regular loop.

I mean, is this not simpler?:

var arr = new [] {1, 2, 3}
foreach (int number in arr)
{
    if(n == 1) { continue; }      
    if(n == -1) { break; }      
}
Yuval Itzchakov
  • 146,575
  • 32
  • 257
  • 321
  • tnx, I guess I should have included in the question how one could implement jump logic in that extension method. – MaYaN Jul 16 '15 at 13:04
  • 1
    @MaYaN I added a remark to my answer. You can find a hack around this, but I guess you'll end up with uglier code. I'd use a regular foreach instead. – Yuval Itzchakov Jul 16 '15 at 13:08
  • I think the use of this extension method should be considered in the context of a codebase where almost everything is functional and linq based. if you have functional methods everywhere then a `foreach` such as the above breaks the harmony :-) the `overly` simplified example in my question was just to get the ball rolling. – MaYaN Jul 16 '15 at 13:14
  • @MaYaN Why does it break "functionality"? Because it isn't LINQ based? LINQ can be of great help to readability, but on the other hand can make terribly unreadable code if used incorrectly. I wouldn't force "LINQ all the things" where it isn't really the place. That, and the fact that LINQ has some performance overhead. – Yuval Itzchakov Jul 16 '15 at 13:17
3

In addition to Yuval's answer I'd like to add that you could implement something like this as follows:

Change the Action<T> into a Func<T, bool> which takes a T parameter and returns a bool result.

The "continue" case could easily be handled by returning from the function upon the condition, thus continuing with the next iteration of the loop.

The "break" case could be handled by returning a bool from the function that indicates whether to continue or not:

public static void ForEach<T>(this IEnumerable<T> sequence, Func<T, bool> action)
{
  foreach (T obj in sequence)
  { 
    if (!action(obj)) 
      break;
  }
}

new [] {1, 2, 3}.ForEach(n => 
{
    if(n == 1) { return true;}      
    if(n == -1) { return false; }  

    // do something 
    ...
    return true;
});
Thorsten Dittmar
  • 55,956
  • 8
  • 91
  • 139
1

Yes, those keyword are limited to while, do, for, and foreach (as Yuval referenced).

This code would resemble roughly the same as you ask:

bool shouldBreak = false;

new [] {1, 2, 3}
.ForEach(n => 
{
    if (!shouldBreak)
    {
        if(n == 1) { /* no action */ }      
        else if(n == -1) { shouldBreak = true; }
        else
        {
            // do something 
        }
    }
});
Patrick Hofman
  • 153,850
  • 22
  • 249
  • 325