从 foreach 语句中返回是否有副作用?

17

与我关于using语句内部返回的问题类似(其答案通常是" 是的,没问题"),我想知道从foreach语句内部返回是否同样不会产生副作用并被认为是可接受的实践,或者当我这样做时,是否在某个内部的枚举中留下了一个悬而未决的指针等。

这里有一个例子:

public string GetCurrentTransaction(string idText)
{
    foreach (var transaction in transactions)
    {
        if (idText.IsEquivalentTo(transaction.IdText))
        {
            return transaction.Content;
        }
    }
    return "";
}
5个回答

19

不,我认为这没有任何问题。

来自foreach, in (C# 参考)

使用goto、return或throw语句也可以退出foreach循环。


5
只要没有实现IDisposable接口(或者你在其周围使用了using块),那就应该没问题。据我所知,这是一种相当常见和被接受的做法,并且正如Astander在他的帖子中提到的那样,foreach的文档也认为这是一种合法的做法。

2
实际上,foreach将处理IEnumerator<>的释放,因此如果枚举器本身是可处理的,则可以正常运行。请参见此问题中的已接受答案:https://dev59.com/YnVC5IYBdhLWcg3woCrN - Lucero

2

除了在方法中从多个点返回(增加了方法的圈复杂度)可能会导致代码不太简洁外,没有其他技术上的担忧。


+1 我同意,这会增加一些复杂性。我会创建一个字符串变量,并在找到文本时进行赋值并从循环中退出。但从技术角度来看,没有什么可担心的(除了其他人提到的IDisposable)。这可能更多是一个编码风格的问题。 - SwDevMan81
4
对于简单的“查找元素并返回它,如果未找到则返回null”,我认为有两个退出点是可以接受的,因为这些函数足够短,因此您可以很容易地发现两个返回点,而且您不必携带另一个“returnValue”变量。 - user253984
2
在我看来,这里没有代码异味。相比于将返回值写入变量并继续到结尾以确保不再执行任何操作,这种方式更易读。而且,相比于有大量嵌套的if语句(if(stillNotFound)stuff),这种方式也更易读。 - Stefan Steinegger

1

我不确定,但我会做出一个有根据的猜测:由于枚举器通常不实现IDisposable接口,所以它应该只是被垃圾回收器回收,因为否则每次使用该枚举器都会泄漏非受控资源。当然,从技术上讲,您可以实现一个具有自身副作用的枚举器...

换句话说,我从来没有对在foreach块中返回感到不好。我希望语言能够处理这些事情,就像在using语句中一样,语言确保对象被处理(通过在finally块中隐式调用Dispose)。


枚举器(继承自IEnumerable<>)确实实现了IDisposable - Lucero
IEnumerator<T> 继承自 IDisposable,这点我之前并不知道。但是,IEnumerator 没有继承 IDisposable。然而,自 C# 2.0 开始的 foreachfinally 块中调用 Dispose,所以语言会处理它,符合我的预期。你可以安全地从 foreach 块中返回。 - OregonGhost

0
据我所记,枚举会一直停留在这个位置,直到下一个foreach循环。然而,这并不是问题,因为任何后续的foreach都会将位置返回到枚举的起始位置。简而言之:它没有任何副作用,除非您依赖于IEnumerator.Current具有特定值(这本来就是不好的)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接