【问题标题】:How can I use 'continue' and `break` in an extension method?如何在扩展方法中使用“继续”和“中断”?
【发布时间】:2015-07-16 13:01:29
【问题描述】:

我定义了如下扩展方法:

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

然后我可以将其用作:

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

我希望能够在我的扩展方法中利用continuebreak,这样我就可以做到:

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 
});

这些关键字只能在forforeachwhiledo-while 循环中使用吗?

【问题讨论】:

  • 恕我直言,这种扩展方法根本没有意义。它只会使您的代码复杂化。为什么不使用foreach 循环?您不必用扩展方法替换所有内容。
  • @Daniel - 我不同意,我是函数式编程linqmorelinq 的忠实粉丝,在我看来(以及我团队中许多其他人的意见)这太多了比其他方法更容易阅读。
  • 对于每个已经在列表 fyi 上
  • 但不在 IEnumerable 上 ;-) 因此它在 MoreLinq 中可用

标签: c# .net morelinq


【解决方案1】:

这些关键字只能在 for、foreach、while 循环中使用吗?

是的。这些语句仅限于循环类型。 As the docs say:

continue 语句将控制权传递给 将其出现的 while、do、for 或 foreach 语句括起来。

And:

break 语句终止 最近的封闭循环或开关 它出现的语句。控制权传递给以下语句 跟随终止的语句,如果有的话。

我建议您使用常规的foreach,它可以自我表达。我认为任何在 ForEach 扩展方法中使用语义的尝试都会导致比使用常规循环更奇怪的代码。

我的意思是,这不是更简单吗?:

var arr = new [] {1, 2, 3}
foreach (int number in arr)
{
    if(n == 1) { continue; }      
    if(n == -1) { break; }      
}

【讨论】:

  • tnx,我想我应该在问题中包含如何在该扩展方法中实现跳转逻辑。
  • @MaYaN 我在回答中添加了一个备注。您可以找到解决此问题的方法,但我想您最终会得到更丑陋的代码。我会改用常规的 foreach。
  • 我认为应该在几乎所有东西都是函数式和基于 linq 的代码库的上下文中考虑使用这种扩展方法。如果您到处都有函数方法,那么上面的foreach 会破坏和谐:-) 我的问题中的overly 简化示例只是为了让球滚动。
  • @MaYaN 为什么会破坏“功能”?因为它不是基于 LINQ 的? LINQ 对可读性有很大帮助,但另一方面,如果使用不当,可能会产生非常不可读的代码。我不会强迫“LINQ all things”在它不是真正的地方。这一点,以及 LINQ 有一些性能开销的事实。
【解决方案2】:

除了 Yuval 的回答,我想补充一点,您可以按如下方式实现:

Action&lt;T&gt; 更改为Func&lt;T, bool&gt;,它接受T 参数并返回bool 结果。

“继续”的情况可以通过根据条件从函数返回来轻松处理,从而继续循环的下一次迭代。

可以通过从指示是否继续的函数返回bool 来处理“中断”情况:

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;
});

【讨论】:

  • 你会想要使用Func&lt;T, bool&gt;而不是Action&lt;T&gt;,因为操作返回无效。
  • @TrevorPilley 当然。我只是要编辑,因为我必须先用谷歌搜索如何从操作中返回值:-)
  • @TrevorPilley:虽然这是事实,但 IMO 并不是投反对票的理由。
  • @TrevorPilley 我修改了我的答案。谢谢大家。
  • @ThorstenDittmar 你怎么有一个 33.6k 的代表却不知道 Func&lt;T, bool&gt; 没有谷歌?
【解决方案3】:

是的,这些关键字仅限于 whiledoforforeach(正如 Yuval 所引用的)。

此代码与您询问的大致相同:

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 
        }
    }
});

【讨论】:

  • 这仍然会遍历所有集合,只是在中断后不做任何事情。它打破了Linq的整个懒惰。
  • 是的。不要使用 LINQ ;) 在这种情况下,for 会做得更好。
猜你喜欢
  • 1970-01-01
  • 2014-02-27
  • 1970-01-01
  • 1970-01-01
  • 2010-10-11
  • 2017-03-16
  • 1970-01-01
  • 1970-01-01
  • 2012-11-25
相关资源
最近更新 更多